From c5c2e4fefde539e1c1753d4ca184c3bf81d496be Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 2 Nov 2010 01:23:58 +0000 Subject: Add timestamps to Topic --- activerecord/test/cases/base_test.rb | 2 +- activerecord/test/cases/reflection_test.rb | 10 +++++----- activerecord/test/schema/schema.rb | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index e63e1fbe09..ceb1272862 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1353,7 +1353,7 @@ class BasicsTest < ActiveRecord::TestCase def test_inspect_instance topic = topics(:first) - assert_equal %(#), topic.inspect + assert_equal %(#), topic.inspect end def test_inspect_new_instance diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index eeb619ac2f..3b9e4f42a6 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -24,25 +24,25 @@ class ReflectionTest < ActiveRecord::TestCase def test_read_attribute_names assert_equal( - %w( id title author_name author_email_address bonus_time written_on last_read content group approved replies_count parent_id parent_title type ).sort, + %w( id title author_name author_email_address bonus_time written_on last_read content group approved replies_count parent_id parent_title type created_at updated_at ).sort, @first.attribute_names ) end def test_columns - assert_equal 14, Topic.columns.length + assert_equal 16, Topic.columns.length end def test_columns_are_returned_in_the_order_they_were_declared column_names = Topic.columns.map { |column| column.name } - assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type group), column_names + assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type group created_at updated_at), column_names end def test_content_columns content_columns = Topic.content_columns content_column_names = content_columns.map {|column| column.name} - assert_equal 10, content_columns.length - assert_equal %w(title author_name author_email_address written_on bonus_time last_read content group approved parent_title).sort, content_column_names.sort + assert_equal 12, content_columns.length + assert_equal %w(title author_name author_email_address written_on bonus_time last_read content group approved parent_title created_at updated_at).sort, content_column_names.sort end def test_column_string_type_and_limit diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index bb80a1ca17..d4eb56c4d7 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -552,6 +552,7 @@ ActiveRecord::Schema.define do t.string :parent_title t.string :type t.string :group + t.timestamps end create_table :toys, :primary_key => :toy_id ,:force => true do |t| -- cgit v1.2.3 From e911ed1f0f1633b0ae1b5146805eee6388b1f02f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 2 Nov 2010 01:42:47 +0000 Subject: Ensure save always updates timestamps when serialized attributes are present --- activerecord/lib/active_record/attribute_methods/dirty.rb | 4 ++++ activerecord/test/cases/dirty_test.rb | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 439880c1fa..78a941b5d4 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -41,6 +41,10 @@ module ActiveRecord end end + def changed? + super || (attributes.keys & self.class.serialized_attributes.keys).present? + end + private # Wrap write_attribute to remember original attribute value. def write_attribute(attr, value) diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index bde93d1c85..b1a54af192 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -395,6 +395,20 @@ class DirtyTest < ActiveRecord::TestCase end end + def test_save_always_should_update_timestamps_when_serialized_attributes_are_present + with_partial_updates(Topic) do + topic = Topic.create!(:content => {:a => "a"}) + topic.save! + + updated_at = topic.updated_at + topic.content[:hello] = 'world' + topic.save! + + assert_not_equal updated_at, topic.updated_at + assert_equal 'world', topic.content[:hello] + end + end + def test_save_should_not_save_serialized_attribute_with_partial_updates_if_not_present with_partial_updates(Topic) do Topic.create!(:author_name => 'Bill', :content => {:a => "a"}) -- cgit v1.2.3 From 18b6aa65389cd10d62dc0005e632a3a2d474dec4 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 2 Nov 2010 01:45:30 +0000 Subject: Make should_record_timestamps? serialization aware rather than object#changed? --- activerecord/lib/active_record/attribute_methods/dirty.rb | 4 ---- activerecord/lib/active_record/timestamp.rb | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 78a941b5d4..439880c1fa 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -41,10 +41,6 @@ module ActiveRecord end end - def changed? - super || (attributes.keys & self.class.serialized_attributes.keys).present? - end - private # Wrap write_attribute to remember original attribute value. def write_attribute(attr, value) diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index a7583f06cc..230adf6b2b 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -61,7 +61,7 @@ module ActiveRecord end def should_record_timestamps? - record_timestamps && (!partial_updates? || changed?) + record_timestamps && (!partial_updates? || changed? || (attributes.keys & self.class.serialized_attributes.keys).present?) end def timestamp_attributes_for_update_in_model -- cgit v1.2.3 From d446392f76c063d9f04396a1d3ca9e314a521671 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 2 Nov 2010 10:47:32 +0000 Subject: Add additional HTTP request methods from the following RFCs: * Hypertext Transfer Protocol -- HTTP/1.1 http://www.ietf.org/rfc/rfc2616.txt) * HTTP Extensions for Distributed Authoring -- WEBDAV http://www.ietf.org/rfc/rfc2518.txt * Versioning Extensions to WebDAV http://www.ietf.org/rfc/rfc3253.txt * Ordered Collections Protocol (WebDAV) http://www.ietf.org/rfc/rfc3648.txt * Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol http://www.ietf.org/rfc/rfc3744.txt * Web Distributed Authoring and Versioning (WebDAV) SEARCH http://www.ietf.org/rfc/rfc5323.txt * PATCH Method for HTTP http://www.ietf.org/rfc/rfc5789.txt [#2809 state:resolved] [#5895 state:resolved] --- actionpack/lib/action_dispatch/http/request.rb | 21 ++++++++++++++-- actionpack/lib/action_dispatch/routing/mapper.rb | 5 ++-- actionpack/test/dispatch/routing_test.rb | 31 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 55a3166f6d..08f30e068d 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -4,6 +4,7 @@ require 'strscan' require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/string/access' +require 'active_support/inflector' require 'action_dispatch/http/headers' module ActionDispatch @@ -44,8 +45,24 @@ module ActionDispatch @env.key?(key) end - HTTP_METHODS = %w(get head put post delete options) - HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h } + # List of HTTP request methods from the following RFCs: + # Hypertext Transfer Protocol -- HTTP/1.1 (http://www.ietf.org/rfc/rfc2616.txt) + # HTTP Extensions for Distributed Authoring -- WEBDAV (http://www.ietf.org/rfc/rfc2518.txt) + # Versioning Extensions to WebDAV (http://www.ietf.org/rfc/rfc3253.txt) + # Ordered Collections Protocol (WebDAV) (http://www.ietf.org/rfc/rfc3648.txt) + # Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (http://www.ietf.org/rfc/rfc3744.txt) + # Web Distributed Authoring and Versioning (WebDAV) SEARCH (http://www.ietf.org/rfc/rfc5323.txt) + # PATCH Method for HTTP (http://www.ietf.org/rfc/rfc5789.txt) + RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT) + RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK) + RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY) + RFC3648 = %w(ORDERPATCH) + RFC3744 = %w(ACL) + RFC5323 = %w(SEARCH) + RFC5789 = %w(PATCH) + + HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789 + HTTP_METHOD_LOOKUP = Hash.new { |h, m| h[m] = m.underscore.to_sym if HTTP_METHODS.include?(m) } # Returns the HTTP \method that the application should see. # In the case where the \method was overridden by a middleware diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 3c7dcea003..1bbb4f1f92 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,6 +1,7 @@ require 'erb' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/object/blank' +require 'active_support/inflector' module ActionDispatch module Routing @@ -186,8 +187,8 @@ module ActionDispatch def request_method_condition if via = @options[:via] - via = Array(via).map { |m| m.to_s.upcase } - { :request_method => Regexp.union(*via) } + via = Array(via).map { |m| m.to_s.dasherize.upcase } + { :request_method => %r[^#{via.join('|')}$] } else { } end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 5c188a60c7..0ac8c249cb 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -2255,3 +2255,34 @@ class TestDefaultScope < ActionDispatch::IntegrationTest end end +class TestHttpMethods < ActionDispatch::IntegrationTest + RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT) + RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK) + RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY) + RFC3648 = %w(ORDERPATCH) + RFC3744 = %w(ACL) + RFC5323 = %w(SEARCH) + RFC5789 = %w(PATCH) + + def simple_app(response) + lambda { |env| [ 200, { 'Content-Type' => 'text/plain' }, [response] ] } + end + + setup do + s = self + @app = ActionDispatch::Routing::RouteSet.new + + @app.draw do + (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method| + match '/' => s.simple_app(method), :via => method.underscore.to_sym + end + end + end + + (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method| + test "request method #{method.underscore} can be matched" do + get '/', nil, 'REQUEST_METHOD' => method + assert_equal method, @response.body + end + end +end -- cgit v1.2.3 From cfcea1d53ae5ce38a7cbeb41e05958dc009988b0 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Fri, 15 Oct 2010 17:46:31 +0300 Subject: Added 'rails plugin new' generator which generates gem plugin skeleton. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This command is based on enginex gem by José Valim. It generates gem structure and ads dummy application into test/dummy. This can be used to start developing any kind of extension for rails 3. --- railties/lib/rails/cli.rb | 7 +- railties/lib/rails/commands/plugin_new.rb | 16 ++ .../rails/plugin_new/plugin_new_generator.rb | 225 +++++++++++++++++++++ .../rails/plugin_new/templates/%name%.gemspec | 9 + .../generators/rails/plugin_new/templates/Gemfile | 11 + .../rails/plugin_new/templates/MIT-LICENSE | 20 ++ .../rails/plugin_new/templates/README.rdoc | 3 + .../generators/rails/plugin_new/templates/Rakefile | 46 +++++ .../rails/plugin_new/templates/gitignore | 6 + .../rails/plugin_new/templates/lib/%name%.rb.tt | 2 + .../plugin_new/templates/rails/application.rb | 12 ++ .../rails/plugin_new/templates/rails/boot.rb | 10 + .../rails/plugin_new/templates/script/rails.tt | 5 + .../plugin_new/templates/test/%name%_test.rb.tt | 7 + .../test/integration/navigation_test.rb.tt | 7 + .../templates/test/support/integration_case.rb | 5 + .../rails/plugin_new/templates/test/test_helper.rb | 22 ++ .../fixtures/lib/plugin_builders/empty_builder.rb | 2 + .../fixtures/lib/plugin_builders/simple_builder.rb | 7 + .../fixtures/lib/plugin_builders/tweak_builder.rb | 7 + .../test/generators/plugin_new_generator_test.rb | 179 ++++++++++++++++ 21 files changed, 607 insertions(+), 1 deletion(-) create mode 100644 railties/lib/rails/commands/plugin_new.rb create mode 100644 railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/Gemfile create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/Rakefile create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/gitignore create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb create mode 100644 railties/test/fixtures/lib/plugin_builders/empty_builder.rb create mode 100644 railties/test/fixtures/lib/plugin_builders/simple_builder.rb create mode 100644 railties/test/fixtures/lib/plugin_builders/tweak_builder.rb create mode 100644 railties/test/generators/plugin_new_generator_test.rb diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb index 1260772605..c8d70d8ffa 100644 --- a/railties/lib/rails/cli.rb +++ b/railties/lib/rails/cli.rb @@ -11,4 +11,9 @@ $:.unshift(railties_path) if File.directory?(railties_path) && !$:.include?(rail require 'rails/ruby_version_check' Signal.trap("INT") { puts; exit } -require 'rails/commands/application' +if ARGV.first == 'plugin' + ARGV.shift + require 'rails/commands/plugin_new' +else + require 'rails/commands/application' +end diff --git a/railties/lib/rails/commands/plugin_new.rb b/railties/lib/rails/commands/plugin_new.rb new file mode 100644 index 0000000000..00a7e30902 --- /dev/null +++ b/railties/lib/rails/commands/plugin_new.rb @@ -0,0 +1,16 @@ +require 'rails/version' +if %w(--version -v).include? ARGV.first + puts "Rails #{Rails::VERSION::STRING}" + exit(0) +end + +if ARGV.first != "new" + ARGV[0] = "--help" +else + ARGV.shift +end + +require 'rails/generators' +require 'rails/generators/rails/plugin_new/plugin_new_generator' + +Rails::Generators::PluginNewGenerator.start diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb new file mode 100644 index 0000000000..239115c07d --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -0,0 +1,225 @@ +require "rails/generators/rails/app/app_generator" + +module Rails + class PluginBuilder + def rakefile + template "Rakefile" + end + + def readme + copy_file "README.rdoc" + end + + def gemfile + template "Gemfile" + end + + def license + template "MIT-LICENSE" + end + + def gemspec + template "%name%.gemspec" + end + + def gitignore + copy_file "gitignore", ".gitignore" + end + + def lib + directory "lib" + end + + def test + directory "test" + end + + def test_dummy + invoke Rails::Generators::AppGenerator, + [ File.expand_path(dummy_path, destination_root) ] + end + + def test_dummy_config + store_application_definition! + template "rails/boot.rb", "#{dummy_path}/config/boot.rb", :force => true + template "rails/application.rb", "#{dummy_path}/config/application.rb", :force => true + end + + def test_dummy_clean + inside dummy_path do + remove_file ".gitignore" + remove_file "db/seeds.rb" + remove_file "doc" + remove_file "Gemfile" + remove_file "lib/tasks" + remove_file "public/images/rails.png" + remove_file "public/index.html" + remove_file "public/robots.txt" + remove_file "README" + remove_file "test" + remove_file "vendor" + end + end + + def script + directory "script" do |content| + "#{shebang}\n" + content + end + chmod "script", 0755, :verbose => false + end + end + + module Generators + class PluginNewGenerator < Base + attr_accessor :rails_template + + add_shebang_option! + + argument :plugin_path, :type => :string + + class_option :builder, :type => :string, :aliases => "-b", + :desc => "Path to a plugin builder (can be a filesystem path or URL)" + + class_option :skip_gemfile, :type => :boolean, :default => false, + :desc => "Don't create a Gemfile" + + class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, + :desc => "Skip Git ignores and keeps" + + class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, + :desc => "Show this help message and quit" + + def self.say_step(message) + @step = (@step || 0) + 1 + class_eval <<-METHOD, __FILE__, __LINE__ + 1 + def step_#{@step} + #{"puts" if @step > 1} + say_status "STEP #{@step}", #{message.inspect} + end + METHOD + end + + def initialize(*args) + raise Error, "Options should be given after plugin name. For details run: rails plugin --help" if args[0].blank? + + @original_wd = Dir.pwd + + super + end + + say_step "Creating gem skeleton" + + def create_root + self.destination_root = File.expand_path(plugin_path, destination_root) + valid_plugin_const? + + empty_directory '.' + FileUtils.cd(destination_root) unless options[:pretend] + end + + def create_root_files + build(:readme) + build(:rakefile) + build(:gemspec) + build(:license) + build(:gitignore) unless options[:skip_git] + build(:gemfile) unless options[:skip_gemfile] + end + + def create_config_files + build(:config) + end + + def create_lib_files + build(:lib) + end + + def create_script_files + build(:script) + end + + def create_test_files + build(:test) unless options[:skip_test_unit] + end + + say_step "Vendoring Rails application at test/dummy" + + def create_test_dummy_files + build(:test_dummy) + end + + say_step "Configuring Rails application" + + def change_config_files + build(:test_dummy_config) + end + + say_step "Removing unneeded files" + + def remove_uneeded_rails_files + build(:test_dummy_clean) + end + + protected + + def self.banner + "rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]" + end + + def builder + @builder ||= begin + if path = options[:builder] + if URI(path).is_a?(URI::HTTP) + contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read } + else + contents = open(File.expand_path(path, @original_wd)) {|io| io.read } + end + + prok = eval("proc { #{contents} }", TOPLEVEL_BINDING, path, 1) + instance_eval(&prok) + end + + builder_class = defined?(::PluginBuilder) ? ::PluginBuilder : Rails::PluginBuilder + builder_class.send(:include, ActionMethods) + builder_class.new(self) + end + end + + def build(meth, *args) + builder.send(meth, *args) if builder.respond_to?(meth) + end + + def name + @name ||= File.basename(destination_root) + end + + def camelized + @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize + end + + def valid_plugin_const? + if camelized =~ /^\d/ + raise Error, "Invalid plugin name #{name}. Please give a name which does not start with numbers." + elsif RESERVED_NAMES.include?(name) + raise Error, "Invalid plugin name #{name}. Please give a name which does not match one of the reserved rails words." + elsif Object.const_defined?(camelized) + raise Error, "Invalid plugin name #{name}, constant #{camelized} is already in use. Please choose another application name." + end + end + + def dummy_path + "test/dummy" + end + + def application_definition + @application_definition ||= begin + unless options[:pretend] + contents = File.read(File.expand_path("#{dummy_path}/config/application.rb", destination_root)) + contents[(contents.index("module Dummy"))..-1] + end + end + end + alias :store_application_definition! :application_definition + end + end +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec new file mode 100644 index 0000000000..3d9bfb22c7 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec @@ -0,0 +1,9 @@ +# Provide a simple gemspec so you can easily use your +# project in your rails apps through git. +Gem::Specification.new do |s| + s.name = "<%= name %>" + s.summary = "Insert <%= camelized %> summary." + s.description = "Insert <%= camelized %> description." + s.files = Dir["lib/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"] + s.version = "0.0.1" +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile new file mode 100644 index 0000000000..83ff86bbd8 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -0,0 +1,11 @@ +source "http://rubygems.org" + +gem "rails", :git => "http://github.com/rails/rails.git" +gem "arel" , :git => "http://github.com/rails/arel.git" +gem "rack" , :git => "http://github.com/rack/rack.git" +gem "capybara", ">= 0.3.9" +gem "sqlite3-ruby", :require => "sqlite3" + +if RUBY_VERSION < '1.9' + gem "ruby-debug", ">= 0.10.3" +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE b/railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE new file mode 100644 index 0000000000..d7a9109894 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright <%= Date.today.year %> YOURNAME + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc b/railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc new file mode 100644 index 0000000000..301d647731 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc @@ -0,0 +1,3 @@ += <%= camelized %> + +This project rocks and uses MIT-LICENSE. \ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile new file mode 100644 index 0000000000..c0e6185ddc --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile @@ -0,0 +1,46 @@ +# encoding: UTF-8 +require 'rubygems' +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end + +require 'rake' +require 'rake/rdoctask' +require 'rake/gempackagetask' + +require 'rake/testtask' + +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.verbose = false +end + +task :default => :test + +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = '<%= camelized %>' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +spec = Gem::Specification.new do |s| + s.name = "<%= name %>" + s.summary = "Insert <%= camelized %> summary." + s.description = "Insert <%= camelized %> description." + s.files = FileList["[A-Z]*", "lib/**/*"] + s.version = "0.0.1" +end + +Rake::GemPackageTask.new(spec) do |pkg| +end + +desc "Install the gem #{spec.name}-#{spec.version}.gem" +task :install do + system("gem install pkg/#{spec.name}-#{spec.version}.gem --no-ri --no-rdoc") +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore b/railties/lib/rails/generators/rails/plugin_new/templates/gitignore new file mode 100644 index 0000000000..1463de6dfb --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/gitignore @@ -0,0 +1,6 @@ +.bundle/ +log/*.log +pkg/ +test/dummy/db/*.sqlite3 +test/dummy/log/*.log +test/dummy/tmp/ \ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt new file mode 100644 index 0000000000..cf77a0b4d3 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt @@ -0,0 +1,2 @@ +module <%= camelized %> +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb new file mode 100644 index 0000000000..fee63ea83e --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb @@ -0,0 +1,12 @@ +require File.expand_path('../boot', __FILE__) + +require "active_model/railtie" +require "active_record/railtie" +require "action_controller/railtie" +require "action_view/railtie" +require "action_mailer/railtie" + +Bundler.require +require "<%= name %>" + +<%= application_definition %> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb new file mode 100644 index 0000000000..eba0681370 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb @@ -0,0 +1,10 @@ +require 'rubygems' +gemfile = File.expand_path('../../../../Gemfile', __FILE__) + +if File.exist?(gemfile) + ENV['BUNDLE_GEMFILE'] = gemfile + require 'bundler' + Bundler.setup +end + +$:.unshift File.expand_path('../../../../lib', __FILE__) \ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt b/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt new file mode 100644 index 0000000000..cd4f7f6ab3 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +ENGINE_PATH = File.expand_path('../..', __FILE__) +load File.expand_path('../../test/dummy/script/rails', __FILE__) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt new file mode 100644 index 0000000000..0a8bbd4aaf --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt @@ -0,0 +1,7 @@ +require 'test_helper' + +class <%= camelized %>Test < ActiveSupport::TestCase + test "truth" do + assert_kind_of Module, <%= camelized %> + end +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt new file mode 100644 index 0000000000..42721899c8 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt @@ -0,0 +1,7 @@ +require 'test_helper' + +class NagivationTest < ActiveSupport::IntegrationCase + test "truth" do + assert_kind_of Dummy::Application, Rails.application + end +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb new file mode 100644 index 0000000000..4cfe3f0e71 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb @@ -0,0 +1,5 @@ +# Define a bare test case to use with Capybara +class ActiveSupport::IntegrationCase < ActiveSupport::TestCase + include Capybara + include Rails.application.routes.url_helpers +end \ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb new file mode 100644 index 0000000000..5c39780a23 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb @@ -0,0 +1,22 @@ +# Configure Rails Envinronment +ENV["RAILS_ENV"] = "test" + +require File.expand_path("../dummy/config/environment.rb", __FILE__) +require "rails/test_help" + +ActionMailer::Base.delivery_method = :test +ActionMailer::Base.perform_deliveries = true +ActionMailer::Base.default_url_options[:host] = "test.com" + +Rails.backtrace_cleaner.remove_silencers! + +# Configure capybara for integration testing +require "capybara/rails" +Capybara.default_driver = :rack_test +Capybara.default_selector = :css + +# Run any available migration +ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__) + +# Load support files +Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } \ No newline at end of file diff --git a/railties/test/fixtures/lib/plugin_builders/empty_builder.rb b/railties/test/fixtures/lib/plugin_builders/empty_builder.rb new file mode 100644 index 0000000000..5c5607621c --- /dev/null +++ b/railties/test/fixtures/lib/plugin_builders/empty_builder.rb @@ -0,0 +1,2 @@ +class PluginBuilder +end diff --git a/railties/test/fixtures/lib/plugin_builders/simple_builder.rb b/railties/test/fixtures/lib/plugin_builders/simple_builder.rb new file mode 100644 index 0000000000..08f6c5535d --- /dev/null +++ b/railties/test/fixtures/lib/plugin_builders/simple_builder.rb @@ -0,0 +1,7 @@ +class PluginBuilder + def gitignore + create_file ".gitignore", <<-R.strip +foobar + R + end +end diff --git a/railties/test/fixtures/lib/plugin_builders/tweak_builder.rb b/railties/test/fixtures/lib/plugin_builders/tweak_builder.rb new file mode 100644 index 0000000000..1e801409a4 --- /dev/null +++ b/railties/test/fixtures/lib/plugin_builders/tweak_builder.rb @@ -0,0 +1,7 @@ +class PluginBuilder < Rails::PluginBuilder + def gitignore + create_file ".gitignore", <<-R.strip +foobar + R + end +end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb new file mode 100644 index 0000000000..3c38dffce2 --- /dev/null +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -0,0 +1,179 @@ +require 'abstract_unit' +require 'generators/generators_test_helper' +require 'rails/generators/rails/plugin_new/plugin_new_generator' + +DEFAULT_PLUGIN_FILES = %w( + .gitignore + Gemfile + Rakefile + bukkits.gemspec + MIT-LICENSE + lib + lib/bukkits.rb + script/rails + test/bukkits_test.rb + test/integration/navigation_test.rb + test/support/integration_case.rb + test/test_helper.rb + test/dummy +) + + +class PluginNewGeneratorTest < Rails::Generators::TestCase + include GeneratorsTestHelper + destination File.join(Rails.root, "tmp/bukkits") + arguments [destination_root] + + def setup + Rails.application = TestApp::Application + super + @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') + + Kernel::silence_warnings do + Thor::Base.shell.send(:attr_accessor, :always_force) + @shell = Thor::Base.shell.new + @shell.send(:always_force=, true) + end + end + + def teardown + super + Rails.application = TestApp::Application.instance + end + + def test_plugin_skeleton_is_created + run_generator + + DEFAULT_PLUGIN_FILES.each{ |path| assert_file path } + end + + def test_plugin_new_generate_pretend + run_generator ["testapp", "--pretend"] + + DEFAULT_PLUGIN_FILES.each{ |path| assert_no_file path } + end + + def test_options_before_plugin_name_raises_an_error + content = capture(:stderr){ run_generator(["--pretend", destination_root]) } + assert_equal "Options should be given after plugin name. For details run: rails plugin --help\n", content + end + + def test_name_collision_raises_an_error + reserved_words = %w[application destroy plugin runner test] + reserved_words.each do |reserved| + content = capture(:stderr){ run_generator [File.join(destination_root, reserved)] } + assert_equal "Invalid plugin name #{reserved}. Please give a name which does not match one of the reserved rails words.\n", content + end + end + + def test_invalid_plugin_name_raises_an_error + content = capture(:stderr){ run_generator [File.join(destination_root, "43-things")] } + assert_equal "Invalid plugin name 43-things. Please give a name which does not start with numbers.\n", content + end + + def test_plugin_name_raises_an_error_if_name_already_used_constant + %w{ String Hash Class Module Set Symbol }.each do |ruby_class| + content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] } + assert_equal "Invalid plugin name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another application name.\n", content + end + end + + def test_invalid_plugin_name_is_fixed + run_generator [File.join(destination_root, "things-43")] + assert_file "things-43/lib/things-43.rb", /module Things43/ + end + + def test_shebang_is_added_to_rails_file + run_generator [destination_root, "--ruby", "foo/bar/baz"] + assert_file "script/rails", /#!foo\/bar\/baz/ + end + + def test_shebang_when_is_the_same_as_default_use_env + run_generator [destination_root, "--ruby", Thor::Util.ruby_command] + assert_file "script/rails", /#!\/usr\/bin\/env/ + end + + def test_generating_test_files + run_generator + assert_file "test/test_helper.rb" + assert_directory "test/support/" + assert_directory "test/integration/" + + assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/ + assert_file "test/integration/navigation_test.rb", /assert_kind_of Dummy::Application, Rails.application/ + assert_file "test/support/integration_case.rb", /class ActiveSupport::IntegrationCase/ + end + +protected + + def action(*args, &block) + silence(:stdout){ generator.send(*args, &block) } + end + +end + +class CustomPluginGeneratorTest < Rails::Generators::TestCase + include GeneratorsTestHelper + tests Rails::Generators::PluginNewGenerator + + destination File.join(Rails.root, "tmp/bukkits") + arguments [destination_root] + + def setup + Rails.application = TestApp::Application + super + @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') + end + + def teardown + super + Object.class_eval { remove_const :PluginBuilder if const_defined?(:PluginBuilder) } + Rails.application = TestApp::Application.instance + end + + def test_builder_option_with_empty_app_builder + FileUtils.cd(destination_root) + run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/empty_builder.rb"]) + DEFAULT_PLUGIN_FILES.each{ |path| assert_no_file path } + end + + def test_builder_option_with_simple_plugin_builder + FileUtils.cd(destination_root) + run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/simple_builder.rb"]) + (DEFAULT_PLUGIN_FILES - ['.gitignore']).each{ |path| assert_no_file path } + assert_file ".gitignore", "foobar" + end + + def test_builder_option_with_relative_path + here = File.expand_path(File.dirname(__FILE__)) + FileUtils.cd(here) + run_generator([destination_root, "-b", "../fixtures/lib/plugin_builders/simple_builder.rb"]) + FileUtils.cd(destination_root) + (DEFAULT_PLUGIN_FILES - ['.gitignore']).each{ |path| assert_no_file path } + assert_file ".gitignore", "foobar" + end + + def test_builder_option_with_tweak_plugin_builder + FileUtils.cd(destination_root) + run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/tweak_builder.rb"]) + DEFAULT_PLUGIN_FILES.each{ |path| assert_file path } + assert_file ".gitignore", "foobar" + end + + def test_builder_option_with_http + path = "http://gist.github.com/103208.txt" + template = "class PluginBuilder; end" + template.instance_eval "def read; self; end" # Make the string respond to read + + generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + capture(:stdout) { generator.invoke_all } + + DEFAULT_PLUGIN_FILES.each{ |path| assert_no_file path } + end + +protected + + def action(*args, &block) + silence(:stdout){ generator.send(*args, &block) } + end +end -- cgit v1.2.3 From b37938eff72fe370ddc84afb656f6b4775053f6a Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 19 Oct 2010 23:26:48 +0200 Subject: Refactored AppGenerator and PluginNewGenerator to inherit from AppBase. --- railties/lib/rails/generators/app_base.rb | 61 ++++++++++++++++++++++ .../rails/generators/rails/app/app_generator.rb | 25 ++++----- .../rails/plugin_new/plugin_new_generator.rb | 50 ++++-------------- 3 files changed, 79 insertions(+), 57 deletions(-) create mode 100644 railties/lib/rails/generators/app_base.rb diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb new file mode 100644 index 0000000000..d66b1345c1 --- /dev/null +++ b/railties/lib/rails/generators/app_base.rb @@ -0,0 +1,61 @@ +require 'digest/md5' +require 'active_support/secure_random' +require 'rails/version' unless defined?(Rails::VERSION) +require 'rbconfig' +require 'open-uri' +require 'uri' + +module Rails + module Generators + class AppBase < Base + def self.say_step(message) + @step = (@step || 0) + 1 + class_eval <<-METHOD, __FILE__, __LINE__ + 1 + def step_#{@step} + #{"puts" if @step > 1} + say_status "STEP #{@step}", #{message.inspect} + end + METHOD + end + + def initialize(*args) + @original_wd = Dir.pwd + + super + end + + protected + + def builder + @builder ||= begin + if path = options[:builder] + if URI(path).is_a?(URI::HTTP) + contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read } + else + contents = open(File.expand_path(path, @original_wd)) {|io| io.read } + end + + prok = eval("proc { #{contents} }", TOPLEVEL_BINDING, path, 1) + instance_eval(&prok) + end + + builder_class = get_builder_class + builder_class.send(:include, ActionMethods) + builder_class.new(self) + end + end + + def build(meth, *args) + builder.send(meth, *args) if builder.respond_to?(meth) + end + + def create_root + self.destination_root = File.expand_path(app_path, destination_root) + valid_const? + + empty_directory '.' + FileUtils.cd(destination_root) unless options[:pretend] + end + end + end +end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 44f9fde0a6..16150c306a 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -1,9 +1,4 @@ -require 'digest/md5' -require 'active_support/secure_random' -require 'rails/version' unless defined?(Rails::VERSION) -require 'rbconfig' -require 'open-uri' -require 'uri' +require 'rails/generators/app_base' module Rails module ActionMethods @@ -158,7 +153,7 @@ module Rails RESERVED_NAMES = %w[application destroy benchmarker profiler plugin runner test] - class AppGenerator < Base + class AppGenerator < AppBase DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) JAVASCRIPTS = %w( prototype jquery ) @@ -210,8 +205,6 @@ module Rails def initialize(*args) raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank? - @original_wd = Dir.pwd - super if !options[:skip_active_record] && !DATABASES.include?(options[:database]) @@ -224,12 +217,8 @@ module Rails end def create_root - self.destination_root = File.expand_path(app_path, destination_root) - valid_app_const? - - empty_directory '.' set_default_accessors! - FileUtils.cd(destination_root) unless options[:pretend] + super end def create_root_files @@ -339,7 +328,7 @@ module Rails instance_eval(&prok) end - builder_class = defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder + builder_class = get_builder_class builder_class.send(:include, ActionMethods) builder_class.new(self) end @@ -388,7 +377,7 @@ module Rails @app_const ||= "#{app_const_base}::Application" end - def valid_app_const? + def valid_const? if app_const =~ /^\d/ raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers." elsif RESERVED_NAMES.include?(app_name) @@ -442,6 +431,10 @@ module Rails empty_directory(destination, config) create_file("#{destination}/.gitkeep") unless options[:skip_git] end + + def get_builder_class + defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder + end end end end diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 239115c07d..9ee7edfc2b 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -1,3 +1,4 @@ +require 'rails/generators/app_base' require "rails/generators/rails/app/app_generator" module Rails @@ -70,12 +71,13 @@ module Rails end module Generators - class PluginNewGenerator < Base + class PluginNewGenerator < AppBase attr_accessor :rails_template add_shebang_option! argument :plugin_path, :type => :string + alias_method :app_path, :plugin_path class_option :builder, :type => :string, :aliases => "-b", :desc => "Path to a plugin builder (can be a filesystem path or URL)" @@ -89,32 +91,17 @@ module Rails class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, :desc => "Show this help message and quit" - def self.say_step(message) - @step = (@step || 0) + 1 - class_eval <<-METHOD, __FILE__, __LINE__ + 1 - def step_#{@step} - #{"puts" if @step > 1} - say_status "STEP #{@step}", #{message.inspect} - end - METHOD - end def initialize(*args) raise Error, "Options should be given after plugin name. For details run: rails plugin --help" if args[0].blank? - @original_wd = Dir.pwd - super end say_step "Creating gem skeleton" def create_root - self.destination_root = File.expand_path(plugin_path, destination_root) - valid_plugin_const? - - empty_directory '.' - FileUtils.cd(destination_root) unless options[:pretend] + super end def create_root_files @@ -166,29 +153,6 @@ module Rails "rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]" end - def builder - @builder ||= begin - if path = options[:builder] - if URI(path).is_a?(URI::HTTP) - contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read } - else - contents = open(File.expand_path(path, @original_wd)) {|io| io.read } - end - - prok = eval("proc { #{contents} }", TOPLEVEL_BINDING, path, 1) - instance_eval(&prok) - end - - builder_class = defined?(::PluginBuilder) ? ::PluginBuilder : Rails::PluginBuilder - builder_class.send(:include, ActionMethods) - builder_class.new(self) - end - end - - def build(meth, *args) - builder.send(meth, *args) if builder.respond_to?(meth) - end - def name @name ||= File.basename(destination_root) end @@ -197,7 +161,7 @@ module Rails @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize end - def valid_plugin_const? + def valid_const? if camelized =~ /^\d/ raise Error, "Invalid plugin name #{name}. Please give a name which does not start with numbers." elsif RESERVED_NAMES.include?(name) @@ -220,6 +184,10 @@ module Rails end end alias :store_application_definition! :application_definition + + def get_builder_class + defined?(::PluginBuilder) ? ::PluginBuilder : Rails::PluginBuilder + end end end end -- cgit v1.2.3 From b8a0fabe184f6c8f926f7869341ca40b6395606a Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 20 Oct 2010 00:47:13 +0200 Subject: Ensure that options for plugin new generator are not passed to application generator --- .../lib/rails/generators/rails/plugin_new/plugin_new_generator.rb | 2 +- railties/test/generators/plugin_new_generator_test.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 9ee7edfc2b..06ef158a51 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -37,7 +37,7 @@ module Rails def test_dummy invoke Rails::Generators::AppGenerator, - [ File.expand_path(dummy_path, destination_root) ] + [ File.expand_path(dummy_path, destination_root) ], {} end def test_dummy_config diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 3c38dffce2..fa00e75132 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -104,6 +104,12 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "test/support/integration_case.rb", /class ActiveSupport::IntegrationCase/ end + def test_ensure_that_plugin_options_are_not_passed_app_generator + output = run_generator [destination_root, "--skip_gemfile"] + assert_no_file "Gemfile" + assert_match /STEP 2.*create Gemfile/m, output + end + protected def action(*args, &block) -- cgit v1.2.3 From bcd414fd10a0e401cfb1de95cc9b2940b1df0ff6 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 20 Oct 2010 01:05:34 +0200 Subject: Add support for templates for rails plugin new --- railties/lib/rails/generators/app_base.rb | 18 ++++++++++++++++++ .../lib/rails/generators/rails/app/app_generator.rb | 16 +--------------- .../rails/plugin_new/plugin_new_generator.rb | 11 +++++++++++ .../test/generators/plugin_new_generator_test.rb | 20 ++++++++++++++++++++ 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index d66b1345c1..ecaf92c683 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -54,8 +54,26 @@ module Rails valid_const? empty_directory '.' + set_default_accessors! FileUtils.cd(destination_root) unless options[:pretend] end + + def apply_rails_template + apply rails_template if rails_template + rescue Thor::Error, LoadError, Errno::ENOENT => e + raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}" + end + + def set_default_accessors! + self.rails_template = case options[:template] + when /^http:\/\// + options[:template] + when String + File.expand_path(options[:template], Dir.pwd) + else + options[:template] + end + end end end end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 16150c306a..8c6ec41e4d 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -217,7 +217,6 @@ module Rails end def create_root - set_default_accessors! super end @@ -299,9 +298,7 @@ module Rails end def apply_rails_template - apply rails_template if rails_template - rescue Thor::Error, LoadError, Errno::ENOENT => e - raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}" + super end def bundle_if_dev_or_edge @@ -338,17 +335,6 @@ module Rails builder.send(meth, *args) if builder.respond_to?(meth) end - def set_default_accessors! - 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) create_file(*args, &block) diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 06ef158a51..9785a6938a 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -82,6 +82,9 @@ module Rails class_option :builder, :type => :string, :aliases => "-b", :desc => "Path to a plugin builder (can be a filesystem path or URL)" + class_option :template, :type => :string, :aliases => "-m", + :desc => "Path to an application template (can be a filesystem path or URL)" + class_option :skip_gemfile, :type => :boolean, :default => false, :desc => "Don't create a Gemfile" @@ -147,6 +150,14 @@ module Rails build(:test_dummy_clean) end + def finish_template + build(:leftovers) + end + + def apply_rails_template + super + end + protected def self.banner diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index fa00e75132..f3672cb6f1 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -110,6 +110,26 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_match /STEP 2.*create Gemfile/m, output end + def test_template_from_dir_pwd + FileUtils.cd(Rails.root) + assert_match /It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"]) + end + + def test_template_raises_an_error_with_invalid_path + content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) } + assert_match /The template \[.*\] could not be loaded/, content + assert_match /non\/existant\/path/, content + end + + def test_template_is_executed_when_supplied + path = "http://gist.github.com/103208.txt" + template = %{ say "It works!" } + template.instance_eval "def read; self; end" # Make the string respond to read + + generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + assert_match /It works!/, silence(:stdout){ generator.invoke_all } + end + protected def action(*args, &block) -- cgit v1.2.3 From bbf02ffea449b32c93e931f7ff2625a8dc736792 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 20 Oct 2010 01:08:21 +0200 Subject: That method is already declared at AppBase --- .../rails/generators/rails/app/app_generator.rb | 23 ---------------------- 1 file changed, 23 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 8c6ec41e4d..9328cdc789 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -312,29 +312,6 @@ module Rails "rails new #{self.arguments.map(&:usage).join(' ')} [options]" end - def builder - @builder ||= begin - if path = options[:builder] - if URI(path).is_a?(URI::HTTP) - contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read } - else - contents = open(File.expand_path(path, @original_wd)) {|io| io.read } - end - - prok = eval("proc { #{contents} }", TOPLEVEL_BINDING, path, 1) - instance_eval(&prok) - end - - builder_class = get_builder_class - builder_class.send(:include, ActionMethods) - builder_class.new(self) - end - end - - def build(meth, *args) - builder.send(meth, *args) if builder.respond_to?(meth) - end - # Define file as an alias to create_file for backwards compatibility. def file(*args, &block) create_file(*args, &block) -- cgit v1.2.3 From 5c8b48ab4b9d08f3e38087214635918e659d72b6 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 20 Oct 2010 06:19:11 +0200 Subject: Added USAGE for rails plugin new --- railties/lib/rails/generators/rails/plugin_new/USAGE | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 railties/lib/rails/generators/rails/plugin_new/USAGE diff --git a/railties/lib/rails/generators/rails/plugin_new/USAGE b/railties/lib/rails/generators/rails/plugin_new/USAGE new file mode 100644 index 0000000000..9a7bf9f396 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/USAGE @@ -0,0 +1,10 @@ +Description: + The 'rails plugin new' command creates a skeleton for developing any + kind of Rails extension with ability to run tests using dummy Rails + application. + +Example: + rails plugin new ~/Code/Ruby/blog + + This generates a skeletal Rails plugin in ~/Code/Ruby/blog. + See the README in the newly created plugin to get going. -- cgit v1.2.3 From e51e9e2db0359355feef71e735a1f9cb764ec929 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 20 Oct 2010 07:59:28 +0200 Subject: Add --dev and --edge options to rails plugin new --- railties/lib/rails/generators/app_base.rb | 34 ++++++++++++++++++++++ .../rails/generators/rails/app/app_generator.rb | 7 +---- .../rails/generators/rails/app/templates/Gemfile | 17 +---------- .../rails/plugin_new/plugin_new_generator.rb | 10 +++++++ .../generators/rails/plugin_new/templates/Gemfile | 5 ++-- .../test/generators/plugin_new_generator_test.rb | 13 +++++++++ 6 files changed, 61 insertions(+), 25 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index ecaf92c683..e0f0242da8 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -74,6 +74,40 @@ module Rails options[:template] end end + + def rails_gemfile_entry + if options.dev? + <<-GEMFILE +gem 'rails', :path => '#{Rails::Generators::RAILS_DEV_PATH}' +gem 'arel', :git => 'git://github.com/rails/arel.git' +gem "rack", :git => "git://github.com/rack/rack.git" + GEMFILE + elsif options.edge? + <<-GEMFILE +gem 'rails', :git => 'git://github.com/rails/rails.git' +gem 'arel', :git => 'git://github.com/rails/arel.git' +gem "rack", :git => "git://github.com/rack/rack.git" + GEMFILE + else + <<-GEMFILE +gem 'rails', '#{Rails::VERSION::STRING}' + +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' +# gem 'arel', :git => 'git://github.com/rails/arel.git' +# gem "rack", :git => "git://github.com/rack/rack.git" + GEMFILE + end + end + + def bundle_if_dev_or_edge + bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') + run "#{bundle_command} install" if dev_or_edge? + end + + def dev_or_edge? + options.dev? || options.edge? + end end end end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 9328cdc789..7c89eabedd 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -302,8 +302,7 @@ module Rails end def bundle_if_dev_or_edge - bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') - run "#{bundle_command} install" if dev_or_edge? + super end protected @@ -354,10 +353,6 @@ module Rails ActiveSupport::SecureRandom.hex(64) end - def dev_or_edge? - options.dev? || options.edge? - end - def gem_for_database # %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) case options[:database] diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 40213b1261..4a37f675ad 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -1,21 +1,6 @@ source 'http://rubygems.org' -<%- if options.dev? -%> -gem 'rails', :path => '<%= Rails::Generators::RAILS_DEV_PATH %>' -gem 'arel', :git => 'git://github.com/rails/arel.git' -gem "rack", :git => "git://github.com/rack/rack.git" -<%- elsif options.edge? -%> -gem 'rails', :git => 'git://github.com/rails/rails.git' -gem 'arel', :git => 'git://github.com/rails/arel.git' -gem "rack", :git => "git://github.com/rack/rack.git" -<%- else -%> -gem 'rails', '<%= Rails::VERSION::STRING %>' - -# Bundle edge Rails instead: -# gem 'rails', :git => 'git://github.com/rails/rails.git' -# gem 'arel', :git => 'git://github.com/rails/arel.git' -# gem "rack", :git => "git://github.com/rack/rack.git" -<%- end -%> +<%= rails_gemfile_entry -%> <% unless options[:skip_active_record] -%> gem '<%= gem_for_database %>'<% if require_for_database %>, :require => '<%= require_for_database %>'<% end %> diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 9785a6938a..3c710b8908 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -91,6 +91,12 @@ module Rails class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, :desc => "Skip Git ignores and keeps" + class_option :dev, :type => :boolean, :default => false, + :desc => "Setup the plugin with Gemfile pointing to your Rails checkout" + + class_option :edge, :type => :boolean, :default => false, + :desc => "Setup the plugin with Gemfile pointing to Rails repository" + class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, :desc => "Show this help message and quit" @@ -158,6 +164,10 @@ module Rails super end + def bundle_if_dev_or_edge + super + end + protected def self.banner diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index 83ff86bbd8..899a9366d3 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -1,8 +1,7 @@ source "http://rubygems.org" -gem "rails", :git => "http://github.com/rails/rails.git" -gem "arel" , :git => "http://github.com/rails/arel.git" -gem "rack" , :git => "http://github.com/rack/rack.git" +<%= rails_gemfile_entry -%> + gem "capybara", ">= 0.3.9" gem "sqlite3-ruby", :require => "sqlite3" diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index f3672cb6f1..638ff8dce5 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -130,6 +130,19 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_match /It works!/, silence(:stdout){ generator.invoke_all } end + def test_dev_option + generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install") + silence(:stdout){ generator.invoke_all } + rails_path = File.expand_path('../../..', Rails.root) + assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/ + end + + def test_edge_option + generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install") + silence(:stdout){ generator.invoke_all } + assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$/ + end + protected def action(*args, &block) -- cgit v1.2.3 From 59d52229f9ddd55a1cf0674c774a8aeb68300ccf Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 20 Oct 2010 20:45:21 +0200 Subject: Change // style regexp to %r{}, to not confuse editors code highlighting --- railties/test/generators/plugin_new_generator_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 638ff8dce5..8f230525bc 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -140,7 +140,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_edge_option generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install") silence(:stdout){ generator.invoke_all } - assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$/ + assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$} end protected -- cgit v1.2.3 From fd1562af8c662fee8a44d244eaed3350ce10e7da Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 20 Oct 2010 21:21:37 +0200 Subject: Ensure that tests run properly --- railties/test/generators/plugin_new_generator_test.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 8f230525bc..0d88d36971 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -143,6 +143,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$} end + def test_ensure_that_tests_works + run_generator + FileUtils.cd destination_root + `bundle install` + assert_match /2 tests, 2 assertions, 0 failures, 0 errors/, `bundle exec rake test` + end + protected def action(*args, &block) -- cgit v1.2.3 From b36fa51a3f56431d8e46c1fff6a6493d3c10607a Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 20 Oct 2010 21:21:14 +0200 Subject: Allow easy overriding of test framework in 'rake plugin new' generator, using PluginBuilder --- .../rails/plugin_new/plugin_new_generator.rb | 35 ++++++++++++++++++---- .../generators/rails/plugin_new/templates/Rakefile | 11 ++----- .../rails/plugin_new/templates/script/rails.tt | 2 +- .../fixtures/lib/plugin_builders/spec_builder.rb | 13 ++++++++ .../test/generators/plugin_new_generator_test.rb | 10 +++++++ 5 files changed, 55 insertions(+), 16 deletions(-) create mode 100644 railties/test/fixtures/lib/plugin_builders/spec_builder.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 3c710b8908..6067c5d87e 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -35,7 +35,7 @@ module Rails directory "test" end - def test_dummy + def generate_test_dummy invoke Rails::Generators::AppGenerator, [ File.expand_path(dummy_path, destination_root) ], {} end @@ -68,6 +68,27 @@ module Rails end chmod "script", 0755, :verbose => false end + + def rakefile_test_tasks + <<-RUBY +require 'rake/testtask' + +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.verbose = false +end + RUBY + end + + def dummy_path + "#{test_path}/dummy" + end + + def test_path + "test" + end end module Generators @@ -141,7 +162,7 @@ module Rails say_step "Vendoring Rails application at test/dummy" def create_test_dummy_files - build(:test_dummy) + build(:generate_test_dummy) end say_step "Configuring Rails application" @@ -192,10 +213,6 @@ module Rails end end - def dummy_path - "test/dummy" - end - def application_definition @application_definition ||= begin unless options[:pretend] @@ -209,6 +226,12 @@ module Rails def get_builder_class defined?(::PluginBuilder) ? ::PluginBuilder : Rails::PluginBuilder end + + [:test_path, :dummy_path, :rakefile_test_tasks].each do |name| + define_method name do + builder.send(name) if builder.respond_to?(name) + end + end end end end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile index c0e6185ddc..af5f672396 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile @@ -10,16 +10,9 @@ require 'rake' require 'rake/rdoctask' require 'rake/gempackagetask' -require 'rake/testtask' +<%= rakefile_test_tasks %> -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.libs << 'test' - t.pattern = 'test/**/*_test.rb' - t.verbose = false -end - -task :default => :test +task :default => :<%= test_path %> Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt b/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt index cd4f7f6ab3..91d9cf079d 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +++ b/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt @@ -2,4 +2,4 @@ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. ENGINE_PATH = File.expand_path('../..', __FILE__) -load File.expand_path('../../test/dummy/script/rails', __FILE__) +load File.expand_path('../../<%= test_path %>/dummy/script/rails', __FILE__) diff --git a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb new file mode 100644 index 0000000000..bdaa1fb8e1 --- /dev/null +++ b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb @@ -0,0 +1,13 @@ +class PluginBuilder < Rails::PluginBuilder + def test + create_file "spec/spec_helper.rb" + end + + def test_path + "spec" + end + + def rakefile_test_tasks + "# spec tasks in rakefile" + end +end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 0d88d36971..a7177914e1 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -217,6 +217,16 @@ class CustomPluginGeneratorTest < Rails::Generators::TestCase DEFAULT_PLUGIN_FILES.each{ |path| assert_no_file path } end + def test_overriding_test_framework + FileUtils.cd(destination_root) + run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/spec_builder.rb"]) + assert_file 'spec/spec_helper.rb' + assert_file 'Rakefile', /task :default => :spec/ + assert_file 'Rakefile', /# spec tasks in rakefile/ + assert_file 'spec/dummy' + assert_file 'script/rails', %r{spec/dummy} + end + protected def action(*args, &block) -- cgit v1.2.3 From ae1debd442113ed9476e776fe27cd95730896b59 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 21 Oct 2010 00:55:08 +0200 Subject: Make tests for app and plugin generators more DRY --- .../rails/plugin_new/plugin_new_generator.rb | 2 +- .../fixtures/lib/app_builders/empty_builder.rb | 2 + .../fixtures/lib/app_builders/simple_builder.rb | 7 + .../fixtures/lib/app_builders/tweak_builder.rb | 7 + railties/test/fixtures/lib/empty_builder.rb | 2 - railties/test/fixtures/lib/simple_builder.rb | 7 - railties/test/fixtures/lib/tweak_builder.rb | 7 - railties/test/generators/app_generator_test.rb | 148 ++--------------- .../test/generators/plugin_new_generator_test.rb | 153 ++---------------- railties/test/generators/shared_generator_tests.rb | 177 +++++++++++++++++++++ 10 files changed, 222 insertions(+), 290 deletions(-) create mode 100644 railties/test/fixtures/lib/app_builders/empty_builder.rb create mode 100644 railties/test/fixtures/lib/app_builders/simple_builder.rb create mode 100644 railties/test/fixtures/lib/app_builders/tweak_builder.rb delete mode 100644 railties/test/fixtures/lib/empty_builder.rb delete mode 100644 railties/test/fixtures/lib/simple_builder.rb delete mode 100644 railties/test/fixtures/lib/tweak_builder.rb create mode 100644 railties/test/generators/shared_generator_tests.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 6067c5d87e..8296f37211 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -123,7 +123,7 @@ end def initialize(*args) - raise Error, "Options should be given after plugin name. For details run: rails plugin --help" if args[0].blank? + raise Error, "Options should be given after the plugin name. For details run: rails plugin --help" if args[0].blank? super end diff --git a/railties/test/fixtures/lib/app_builders/empty_builder.rb b/railties/test/fixtures/lib/app_builders/empty_builder.rb new file mode 100644 index 0000000000..babd9c2461 --- /dev/null +++ b/railties/test/fixtures/lib/app_builders/empty_builder.rb @@ -0,0 +1,2 @@ +class AppBuilder +end \ No newline at end of file diff --git a/railties/test/fixtures/lib/app_builders/simple_builder.rb b/railties/test/fixtures/lib/app_builders/simple_builder.rb new file mode 100644 index 0000000000..993d3a2aa2 --- /dev/null +++ b/railties/test/fixtures/lib/app_builders/simple_builder.rb @@ -0,0 +1,7 @@ +class AppBuilder + def gitignore + create_file ".gitignore", <<-R.strip +foobar + R + end +end diff --git a/railties/test/fixtures/lib/app_builders/tweak_builder.rb b/railties/test/fixtures/lib/app_builders/tweak_builder.rb new file mode 100644 index 0000000000..cb50be01cb --- /dev/null +++ b/railties/test/fixtures/lib/app_builders/tweak_builder.rb @@ -0,0 +1,7 @@ +class AppBuilder < Rails::AppBuilder + def gitignore + create_file ".gitignore", <<-R.strip +foobar + R + end +end diff --git a/railties/test/fixtures/lib/empty_builder.rb b/railties/test/fixtures/lib/empty_builder.rb deleted file mode 100644 index babd9c2461..0000000000 --- a/railties/test/fixtures/lib/empty_builder.rb +++ /dev/null @@ -1,2 +0,0 @@ -class AppBuilder -end \ No newline at end of file diff --git a/railties/test/fixtures/lib/simple_builder.rb b/railties/test/fixtures/lib/simple_builder.rb deleted file mode 100644 index 47dcdc0d96..0000000000 --- a/railties/test/fixtures/lib/simple_builder.rb +++ /dev/null @@ -1,7 +0,0 @@ -class AppBuilder - def configru - create_file "config.ru", <<-R.strip -run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] } - R - end -end \ No newline at end of file diff --git a/railties/test/fixtures/lib/tweak_builder.rb b/railties/test/fixtures/lib/tweak_builder.rb deleted file mode 100644 index eed20ecc9b..0000000000 --- a/railties/test/fixtures/lib/tweak_builder.rb +++ /dev/null @@ -1,7 +0,0 @@ -class AppBuilder < Rails::AppBuilder - def configru - create_file "config.ru", <<-R.strip -run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] } - R - end -end \ No newline at end of file diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index c7339cb8d2..1f0ef922cd 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -1,6 +1,7 @@ require 'abstract_unit' require 'generators/generators_test_helper' require 'rails/generators/rails/app/app_generator' +require 'generators/shared_generator_tests.rb' DEFAULT_APP_FILES = %w( .gitignore @@ -40,36 +41,10 @@ DEFAULT_APP_FILES = %w( class AppGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments [destination_root] + include SharedGeneratorTests - def setup - Rails.application = TestApp::Application - super - Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) - @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') - - Kernel::silence_warnings do - Thor::Base.shell.send(:attr_accessor, :always_force) - @shell = Thor::Base.shell.new - @shell.send(:always_force=, true) - end - end - - def teardown - super - Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) - Rails.application = TestApp::Application.instance - end - - def test_application_skeleton_is_created - run_generator - - DEFAULT_APP_FILES.each{ |path| assert_file path } - end - - def test_application_generate_pretend - run_generator ["testapp", "--pretend"] - - DEFAULT_APP_FILES.each{ |path| assert_no_file path } + def default_files + ::DEFAULT_APP_FILES end def test_application_controller_and_layout_files @@ -78,19 +53,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_file "public/stylesheets/application.css" end - def test_options_before_application_name_raises_an_error - content = capture(:stderr){ run_generator(["--skip-active-record", destination_root]) } - assert_equal "Options should be given after the application name. For details run: rails --help\n", content - end - - def test_name_collision_raises_an_error - reserved_words = %w[application destroy plugin runner test] - reserved_words.each do |reserved| - content = capture(:stderr){ run_generator [File.join(destination_root, reserved)] } - assert_equal "Invalid application name #{reserved}. Please give a name which does not match one of the reserved rails words.\n", content - end - end - def test_invalid_database_option_raises_an_error content = capture(:stderr){ run_generator([destination_root, "-d", "unknown"]) } assert_match /Invalid value for \-\-database option/, content @@ -101,13 +63,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_equal "Invalid application name 43-things. Please give a name which does not start with numbers.\n", content end - def test_application_name_raises_an_error_if_name_already_used_constant - %w{ String Hash Class Module Set Symbol }.each do |ruby_class| - content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] } - assert_equal "Invalid application name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another application name.\n", content - end - end - def test_invalid_application_name_is_fixed run_generator [File.join(destination_root, "things-43")] assert_file "things-43/config/environment.rb", /Things43::Application\.initialize!/ @@ -217,36 +172,11 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "public/javascripts/rails.js", /jQuery/ end - def test_shebang_is_added_to_rails_file - run_generator [destination_root, "--ruby", "foo/bar/baz"] - assert_file "script/rails", /#!foo\/bar\/baz/ - end - - def test_shebang_when_is_the_same_as_default_use_env - run_generator [destination_root, "--ruby", Thor::Util.ruby_command] - assert_file "script/rails", /#!\/usr\/bin\/env/ - end - def test_template_from_dir_pwd FileUtils.cd(Rails.root) assert_match /It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"]) end - def test_template_raises_an_error_with_invalid_path - content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) } - assert_match /The template \[.*\] could not be loaded/, content - assert_match /non\/existant\/path/, content - end - - def test_template_is_executed_when_supplied - path = "http://gist.github.com/103208.txt" - template = %{ say "It works!" } - template.instance_eval "def read; self; end" # Make the string respond to read - - generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) - assert_match /It works!/, silence(:stdout){ generator.invoke_all } - end - def test_usage_read_from_file File.expects(:read).returns("USAGE FROM FILE") assert_equal "USAGE FROM FILE", Rails::Generators::AppGenerator.desc @@ -266,19 +196,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file 'lib/test_file.rb', 'heres test data' end - def test_dev_option - generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install") - silence(:stdout){ generator.invoke_all } - rails_path = File.expand_path('../../..', Rails.root) - assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/ - end - - def test_edge_option - generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install") - silence(:stdout){ generator.invoke_all } - assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$/ - end - protected def action(*args, &block) @@ -292,62 +209,21 @@ class CustomAppGeneratorTest < Rails::Generators::TestCase tests Rails::Generators::AppGenerator arguments [destination_root] + include SharedCustomGeneratorTests - def setup - Rails.application = TestApp::Application - super - Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) - @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') - end - - def teardown - super - Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) - Object.class_eval { remove_const :AppBuilder if const_defined?(:AppBuilder) } - Rails.application = TestApp::Application.instance - end - - def test_builder_option_with_empty_app_builder - FileUtils.cd(Rails.root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/empty_builder.rb"]) - DEFAULT_APP_FILES.each{ |path| assert_no_file path } - end - - def test_builder_option_with_simple_app_builder - FileUtils.cd(Rails.root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/simple_builder.rb"]) - (DEFAULT_APP_FILES - ['config.ru']).each{ |path| assert_no_file path } - assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }] - end - - def test_builder_option_with_relative_path - here = File.expand_path(File.dirname(__FILE__)) - FileUtils.cd(here) - run_generator([destination_root, "-b", "../fixtures/lib/simple_builder.rb"]) - (DEFAULT_APP_FILES - ['config.ru']).each{ |path| assert_no_file path } - assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }] +protected + def default_files + ::DEFAULT_APP_FILES end - def test_builder_option_with_tweak_app_builder - FileUtils.cd(Rails.root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/tweak_builder.rb"]) - DEFAULT_APP_FILES.each{ |path| assert_file path } - assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }] + def builders_dir + "app_builders" end - def test_builder_option_with_http - path = "http://gist.github.com/103208.txt" - template = "class AppBuilder; end" - template.instance_eval "def read; self; end" # Make the string respond to read - - generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) - capture(:stdout) { generator.invoke_all } - - DEFAULT_APP_FILES.each{ |path| assert_no_file path } + def builder_class + :AppBuilder end -protected - def action(*args, &block) silence(:stdout){ generator.send(*args, &block) } end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index a7177914e1..e8a9c8ff51 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -1,6 +1,7 @@ require 'abstract_unit' require 'generators/generators_test_helper' require 'rails/generators/rails/plugin_new/plugin_new_generator' +require 'generators/shared_generator_tests.rb' DEFAULT_PLUGIN_FILES = %w( .gitignore @@ -23,47 +24,10 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper destination File.join(Rails.root, "tmp/bukkits") arguments [destination_root] + include SharedGeneratorTests - def setup - Rails.application = TestApp::Application - super - @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') - - Kernel::silence_warnings do - Thor::Base.shell.send(:attr_accessor, :always_force) - @shell = Thor::Base.shell.new - @shell.send(:always_force=, true) - end - end - - def teardown - super - Rails.application = TestApp::Application.instance - end - - def test_plugin_skeleton_is_created - run_generator - - DEFAULT_PLUGIN_FILES.each{ |path| assert_file path } - end - - def test_plugin_new_generate_pretend - run_generator ["testapp", "--pretend"] - - DEFAULT_PLUGIN_FILES.each{ |path| assert_no_file path } - end - - def test_options_before_plugin_name_raises_an_error - content = capture(:stderr){ run_generator(["--pretend", destination_root]) } - assert_equal "Options should be given after plugin name. For details run: rails plugin --help\n", content - end - - def test_name_collision_raises_an_error - reserved_words = %w[application destroy plugin runner test] - reserved_words.each do |reserved| - content = capture(:stderr){ run_generator [File.join(destination_root, reserved)] } - assert_equal "Invalid plugin name #{reserved}. Please give a name which does not match one of the reserved rails words.\n", content - end + def default_files + ::DEFAULT_PLUGIN_FILES end def test_invalid_plugin_name_raises_an_error @@ -71,28 +35,11 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_equal "Invalid plugin name 43-things. Please give a name which does not start with numbers.\n", content end - def test_plugin_name_raises_an_error_if_name_already_used_constant - %w{ String Hash Class Module Set Symbol }.each do |ruby_class| - content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] } - assert_equal "Invalid plugin name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another application name.\n", content - end - end - def test_invalid_plugin_name_is_fixed run_generator [File.join(destination_root, "things-43")] assert_file "things-43/lib/things-43.rb", /module Things43/ end - def test_shebang_is_added_to_rails_file - run_generator [destination_root, "--ruby", "foo/bar/baz"] - assert_file "script/rails", /#!foo\/bar\/baz/ - end - - def test_shebang_when_is_the_same_as_default_use_env - run_generator [destination_root, "--ruby", Thor::Util.ruby_command] - assert_file "script/rails", /#!\/usr\/bin\/env/ - end - def test_generating_test_files run_generator assert_file "test/test_helper.rb" @@ -115,34 +62,6 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_match /It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"]) end - def test_template_raises_an_error_with_invalid_path - content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) } - assert_match /The template \[.*\] could not be loaded/, content - assert_match /non\/existant\/path/, content - end - - def test_template_is_executed_when_supplied - path = "http://gist.github.com/103208.txt" - template = %{ say "It works!" } - template.instance_eval "def read; self; end" # Make the string respond to read - - generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) - assert_match /It works!/, silence(:stdout){ generator.invoke_all } - end - - def test_dev_option - generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install") - silence(:stdout){ generator.invoke_all } - rails_path = File.expand_path('../../..', Rails.root) - assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/ - end - - def test_edge_option - generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install") - silence(:stdout){ generator.invoke_all } - assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$} - end - def test_ensure_that_tests_works run_generator FileUtils.cd destination_root @@ -164,58 +83,7 @@ class CustomPluginGeneratorTest < Rails::Generators::TestCase destination File.join(Rails.root, "tmp/bukkits") arguments [destination_root] - - def setup - Rails.application = TestApp::Application - super - @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') - end - - def teardown - super - Object.class_eval { remove_const :PluginBuilder if const_defined?(:PluginBuilder) } - Rails.application = TestApp::Application.instance - end - - def test_builder_option_with_empty_app_builder - FileUtils.cd(destination_root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/empty_builder.rb"]) - DEFAULT_PLUGIN_FILES.each{ |path| assert_no_file path } - end - - def test_builder_option_with_simple_plugin_builder - FileUtils.cd(destination_root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/simple_builder.rb"]) - (DEFAULT_PLUGIN_FILES - ['.gitignore']).each{ |path| assert_no_file path } - assert_file ".gitignore", "foobar" - end - - def test_builder_option_with_relative_path - here = File.expand_path(File.dirname(__FILE__)) - FileUtils.cd(here) - run_generator([destination_root, "-b", "../fixtures/lib/plugin_builders/simple_builder.rb"]) - FileUtils.cd(destination_root) - (DEFAULT_PLUGIN_FILES - ['.gitignore']).each{ |path| assert_no_file path } - assert_file ".gitignore", "foobar" - end - - def test_builder_option_with_tweak_plugin_builder - FileUtils.cd(destination_root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/tweak_builder.rb"]) - DEFAULT_PLUGIN_FILES.each{ |path| assert_file path } - assert_file ".gitignore", "foobar" - end - - def test_builder_option_with_http - path = "http://gist.github.com/103208.txt" - template = "class PluginBuilder; end" - template.instance_eval "def read; self; end" # Make the string respond to read - - generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) - capture(:stdout) { generator.invoke_all } - - DEFAULT_PLUGIN_FILES.each{ |path| assert_no_file path } - end + include SharedCustomGeneratorTests def test_overriding_test_framework FileUtils.cd(destination_root) @@ -228,6 +96,17 @@ class CustomPluginGeneratorTest < Rails::Generators::TestCase end protected + def default_files + ::DEFAULT_PLUGIN_FILES + end + + def builder_class + :PluginBuilder + end + + def builders_dir + "plugin_builders" + end def action(*args, &block) silence(:stdout){ generator.send(*args, &block) } diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb new file mode 100644 index 0000000000..71cde6785c --- /dev/null +++ b/railties/test/generators/shared_generator_tests.rb @@ -0,0 +1,177 @@ +module SharedGeneratorTests + def setup + Rails.application = TestApp::Application + super + Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) + @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') + + Kernel::silence_warnings do + Thor::Base.shell.send(:attr_accessor, :always_force) + @shell = Thor::Base.shell.new + @shell.send(:always_force=, true) + end + end + + def teardown + super + Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) + Rails.application = TestApp::Application.instance + end + + def test_skeleton_is_created + run_generator + + default_files.each{ |path| assert_file path } + end + + def test_plugin_new_generate_pretend + run_generator ["testapp", "--pretend"] + + default_files.each{ |path| assert_no_file path } + end + + def test_options_before_application_name_raises_an_error + content = capture(:stderr){ run_generator(["--pretend", destination_root]) } + assert_match /Options should be given after the \w+ name. For details run: rails( plugin)? --help\n/, content + end + + def test_name_collision_raises_an_error + reserved_words = %w[application destroy plugin runner test] + reserved_words.each do |reserved| + content = capture(:stderr){ run_generator [File.join(destination_root, reserved)] } + assert_match /Invalid \w+ name #{reserved}. Please give a name which does not match one of the reserved rails words.\n/, content + end + end + + def test_name_raises_an_error_if_name_already_used_constant + %w{ String Hash Class Module Set Symbol }.each do |ruby_class| + content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] } + assert_match /Invalid \w+ name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another \w+ name.\n/, content + end + end + + def test_shebang_is_added_to_rails_file + run_generator [destination_root, "--ruby", "foo/bar/baz"] + assert_file "script/rails", /#!foo\/bar\/baz/ + end + + def test_shebang_when_is_the_same_as_default_use_env + run_generator [destination_root, "--ruby", Thor::Util.ruby_command] + assert_file "script/rails", /#!\/usr\/bin\/env/ + end + + def test_template_raises_an_error_with_invalid_path + content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) } + assert_match /The template \[.*\] could not be loaded/, content + assert_match /non\/existant\/path/, content + end + + def test_template_is_executed_when_supplied + path = "http://gist.github.com/103208.txt" + template = %{ say "It works!" } + template.instance_eval "def read; self; end" # Make the string respond to read + + generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + assert_match /It works!/, silence(:stdout){ generator.invoke_all } + end + + def test_dev_option + generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install") + silence(:stdout){ generator.invoke_all } + rails_path = File.expand_path('../../..', Rails.root) + assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/ + end + + def test_edge_option + generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install") + silence(:stdout){ generator.invoke_all } + assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$} + end + + def test_template_raises_an_error_with_invalid_path + content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) } + assert_match /The template \[.*\] could not be loaded/, content + assert_match /non\/existant\/path/, content + end + + def test_template_is_executed_when_supplied + path = "http://gist.github.com/103208.txt" + template = %{ say "It works!" } + template.instance_eval "def read; self; end" # Make the string respond to read + + generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + assert_match /It works!/, silence(:stdout){ generator.invoke_all } + end + + def test_dev_option + generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install") + silence(:stdout){ generator.invoke_all } + rails_path = File.expand_path('../../..', Rails.root) + assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/ + end + + def test_edge_option + generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install") + silence(:stdout){ generator.invoke_all } + assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$} + end +end + +module SharedCustomGeneratorTests + def setup + Rails.application = TestApp::Application + super + Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) + @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') + end + + def teardown + super + Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) + Object.class_eval do + remove_const :AppBuilder if const_defined?(:AppBuilder) + remove_const :PluginBuilder if const_defined?(:PluginBuilder) + end + Rails.application = TestApp::Application.instance + end + + def test_builder_option_with_empty_app_builder + FileUtils.cd(destination_root) + run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/empty_builder.rb"]) + default_files.each{ |path| assert_no_file path } + end + + def test_builder_option_with_simple_plugin_builder + FileUtils.cd(destination_root) + run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/simple_builder.rb"]) + (default_files - ['.gitignore']).each{ |path| assert_no_file path } + assert_file ".gitignore", "foobar" + end + + def test_builder_option_with_relative_path + here = File.expand_path(File.dirname(__FILE__)) + FileUtils.cd(here) + run_generator([destination_root, "-b", "../fixtures/lib/#{builders_dir}/simple_builder.rb"]) + FileUtils.cd(destination_root) + (default_files - ['.gitignore']).each{ |path| assert_no_file path } + assert_file ".gitignore", "foobar" + end + + def test_builder_option_with_tweak_plugin_builder + FileUtils.cd(destination_root) + run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/tweak_builder.rb"]) + default_files.each{ |path| assert_file path } + assert_file ".gitignore", "foobar" + end + + def test_builder_option_with_http + path = "http://gist.github.com/103208.txt" + template = "class #{builder_class}; end" + template.instance_eval "def read; self; end" # Make the string respond to read + + generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + capture(:stdout) { generator.invoke_all } + + default_files.each{ |path| assert_no_file path } + end +end -- cgit v1.2.3 From 48fef64cb5d38b2ac81a483bb0fad89c2134dcdc Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 21 Oct 2010 15:23:07 +0200 Subject: Builder should not be responsible for running store_application_definition method --- railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 8296f37211..2fdd67944e 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -41,7 +41,6 @@ module Rails end def test_dummy_config - store_application_definition! template "rails/boot.rb", "#{dummy_path}/config/boot.rb", :force => true template "rails/application.rb", "#{dummy_path}/config/application.rb", :force => true end @@ -168,6 +167,7 @@ end say_step "Configuring Rails application" def change_config_files + store_application_definition! build(:test_dummy_config) end -- cgit v1.2.3 From ac8f9276f5a5e8dea5d68c20daf5f5a69a299b88 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 21 Oct 2010 15:25:41 +0200 Subject: We don't need gem tasks, we have a gemspec --- .../generators/rails/plugin_new/templates/Rakefile | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile index af5f672396..3c53b677a0 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile @@ -8,7 +8,6 @@ end require 'rake' require 'rake/rdoctask' -require 'rake/gempackagetask' <%= rakefile_test_tasks %> @@ -21,19 +20,3 @@ Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.rdoc_files.include('README.rdoc') rdoc.rdoc_files.include('lib/**/*.rb') end - -spec = Gem::Specification.new do |s| - s.name = "<%= name %>" - s.summary = "Insert <%= camelized %> summary." - s.description = "Insert <%= camelized %> description." - s.files = FileList["[A-Z]*", "lib/**/*"] - s.version = "0.0.1" -end - -Rake::GemPackageTask.new(spec) do |pkg| -end - -desc "Install the gem #{spec.name}-#{spec.version}.gem" -task :install do - system("gem install pkg/#{spec.name}-#{spec.version}.gem --no-ri --no-rdoc") -end -- cgit v1.2.3 From 68295bc69349fc4fd4f8fa2023cf369b70039848 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sat, 23 Oct 2010 18:24:04 +0200 Subject: Remove integration tests and ActionModel/ActiveRecord calls from 'rake plugin new' generator, it shouldn't be available as default option --- .../generators/rails/plugin_new/plugin_new_generator.rb | 5 +++-- .../rails/generators/rails/plugin_new/templates/Gemfile | 3 --- .../rails/plugin_new/templates/rails/application.rb | 6 +----- .../templates/test/integration/navigation_test.rb.tt | 7 ------- .../plugin_new/templates/test/support/integration_case.rb | 5 ----- .../rails/plugin_new/templates/test/test_helper.rb | 14 +------------- railties/test/generators/app_generator_test.rb | 2 +- railties/test/generators/plugin_new_generator_test.rb | 8 +------- 8 files changed, 7 insertions(+), 43 deletions(-) delete mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt delete mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 2fdd67944e..67b9c968d7 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -215,8 +215,9 @@ end def application_definition @application_definition ||= begin - unless options[:pretend] - contents = File.read(File.expand_path("#{dummy_path}/config/application.rb", destination_root)) + dummy_application_path = File.expand_path("#{dummy_path}/config/application.rb", destination_root) + unless options[:pretend] || !File.exists?(dummy_application_path) + contents = File.read(dummy_application_path) contents[(contents.index("module Dummy"))..-1] end end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index 899a9366d3..53a925d976 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -2,9 +2,6 @@ source "http://rubygems.org" <%= rails_gemfile_entry -%> -gem "capybara", ">= 0.3.9" -gem "sqlite3-ruby", :require => "sqlite3" - if RUBY_VERSION < '1.9' gem "ruby-debug", ">= 0.10.3" end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb index fee63ea83e..ce655ba7e5 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb @@ -1,10 +1,6 @@ require File.expand_path('../boot', __FILE__) -require "active_model/railtie" -require "active_record/railtie" -require "action_controller/railtie" -require "action_view/railtie" -require "action_mailer/railtie" +require 'rails/all' Bundler.require require "<%= name %>" diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt deleted file mode 100644 index 42721899c8..0000000000 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt +++ /dev/null @@ -1,7 +0,0 @@ -require 'test_helper' - -class NagivationTest < ActiveSupport::IntegrationCase - test "truth" do - assert_kind_of Dummy::Application, Rails.application - end -end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb deleted file mode 100644 index 4cfe3f0e71..0000000000 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Define a bare test case to use with Capybara -class ActiveSupport::IntegrationCase < ActiveSupport::TestCase - include Capybara - include Rails.application.routes.url_helpers -end \ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb index 5c39780a23..791b901593 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb @@ -4,19 +4,7 @@ ENV["RAILS_ENV"] = "test" require File.expand_path("../dummy/config/environment.rb", __FILE__) require "rails/test_help" -ActionMailer::Base.delivery_method = :test -ActionMailer::Base.perform_deliveries = true -ActionMailer::Base.default_url_options[:host] = "test.com" - Rails.backtrace_cleaner.remove_silencers! -# Configure capybara for integration testing -require "capybara/rails" -Capybara.default_driver = :rack_test -Capybara.default_selector = :css - -# Run any available migration -ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__) - # Load support files -Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } \ No newline at end of file +Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 1f0ef922cd..42a49eb03c 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -145,7 +145,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_test_unit_is_skipped_if_required run_generator [destination_root, "--skip-test-unit"] - assert_no_file "test" + assert_no_file "test" end def test_javascript_is_skipped_if_required diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index e8a9c8ff51..2049d31b18 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -13,8 +13,6 @@ DEFAULT_PLUGIN_FILES = %w( lib/bukkits.rb script/rails test/bukkits_test.rb - test/integration/navigation_test.rb - test/support/integration_case.rb test/test_helper.rb test/dummy ) @@ -43,12 +41,8 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_generating_test_files run_generator assert_file "test/test_helper.rb" - assert_directory "test/support/" - assert_directory "test/integration/" assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/ - assert_file "test/integration/navigation_test.rb", /assert_kind_of Dummy::Application, Rails.application/ - assert_file "test/support/integration_case.rb", /class ActiveSupport::IntegrationCase/ end def test_ensure_that_plugin_options_are_not_passed_app_generator @@ -66,7 +60,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase run_generator FileUtils.cd destination_root `bundle install` - assert_match /2 tests, 2 assertions, 0 failures, 0 errors/, `bundle exec rake test` + assert_match /1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test` end protected -- cgit v1.2.3 From d995953869ca09906af8f5c5058d47cb66bc2467 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sat, 23 Oct 2010 20:42:01 +0200 Subject: DRY up app generator and plugin new generator. Moved shared options to AppBase generator --- railties/lib/rails/generators/app_base.rb | 28 +++++++++++++++++++++ .../rails/generators/rails/app/app_generator.rb | 26 +------------------ .../rails/plugin_new/plugin_new_generator.rb | 29 ++-------------------- 3 files changed, 31 insertions(+), 52 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index e0f0242da8..ad44d9a14e 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -8,6 +8,34 @@ require 'uri' module Rails module Generators class AppBase < Base + attr_accessor :rails_template + add_shebang_option! + + argument :app_path, :type => :string + + def self.add_shared_options_for(name) + class_option :builder, :type => :string, :aliases => "-b", + :desc => "Path to a #{name} builder (can be a filesystem path or URL)" + + class_option :template, :type => :string, :aliases => "-m", + :desc => "Path to an #{name} template (can be a filesystem path or URL)" + + class_option :skip_gemfile, :type => :boolean, :default => false, + :desc => "Don't create a Gemfile" + + class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, + :desc => "Skip Git ignores and keeps" + + class_option :dev, :type => :boolean, :default => false, + :desc => "Setup the #{name} with Gemfile pointing to your Rails checkout" + + class_option :edge, :type => :boolean, :default => false, + :desc => "Setup the #{name} with Gemfile pointing to Rails repository" + + class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, + :desc => "Show this help message and quit" + end + def self.say_step(message) @step = (@step || 0) + 1 class_eval <<-METHOD, __FILE__, __LINE__ + 1 diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 7c89eabedd..04c2e3738a 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -157,10 +157,7 @@ module Rails DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) JAVASCRIPTS = %w( prototype jquery ) - attr_accessor :rails_template - add_shebang_option! - - argument :app_path, :type => :string + add_shared_options_for "application" class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3", :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})" @@ -168,21 +165,6 @@ module Rails class_option :javascript, :type => :string, :aliases => "-j", :default => "prototype", :desc => "Preconfigure for selected javascript library (options: #{JAVASCRIPTS.join('/')})" - class_option :builder, :type => :string, :aliases => "-b", - :desc => "Path to an application builder (can be a filesystem path or URL)" - - class_option :template, :type => :string, :aliases => "-m", - :desc => "Path to an application template (can be a filesystem path or URL)" - - class_option :dev, :type => :boolean, :default => false, - :desc => "Setup the application with Gemfile pointing to your Rails checkout" - - class_option :edge, :type => :boolean, :default => false, - :desc => "Setup the application with Gemfile pointing to Rails repository" - - class_option :skip_gemfile, :type => :boolean, :default => false, - :desc => "Don't create a Gemfile" - class_option :skip_active_record, :type => :boolean, :aliases => "-O", :default => false, :desc => "Skip Active Record files" @@ -192,16 +174,10 @@ module Rails class_option :skip_javascript, :type => :boolean, :aliases => "-J", :default => false, :desc => "Skip javascript files" - class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, - :desc => "Skip Git ignores and keeps" - # Add bin/rails options class_option :version, :type => :boolean, :aliases => "-v", :group => :rails, :desc => "Show Rails version number and quit" - class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, - :desc => "Show this help message and quit" - def initialize(*args) raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank? diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 67b9c968d7..9c0d83cd70 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -92,34 +92,9 @@ end module Generators class PluginNewGenerator < AppBase - attr_accessor :rails_template - - add_shebang_option! - - argument :plugin_path, :type => :string - alias_method :app_path, :plugin_path - - class_option :builder, :type => :string, :aliases => "-b", - :desc => "Path to a plugin builder (can be a filesystem path or URL)" - - class_option :template, :type => :string, :aliases => "-m", - :desc => "Path to an application template (can be a filesystem path or URL)" - - class_option :skip_gemfile, :type => :boolean, :default => false, - :desc => "Don't create a Gemfile" - - class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, - :desc => "Skip Git ignores and keeps" - - class_option :dev, :type => :boolean, :default => false, - :desc => "Setup the plugin with Gemfile pointing to your Rails checkout" - - class_option :edge, :type => :boolean, :default => false, - :desc => "Setup the plugin with Gemfile pointing to Rails repository" - - class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, - :desc => "Show this help message and quit" + add_shared_options_for "plugin" + alias_method :plugin_path, :app_path def initialize(*args) raise Error, "Options should be given after the plugin name. For details run: rails plugin --help" if args[0].blank? -- cgit v1.2.3 From fdbd9df21e0063da4b34346c54fbe21ac9583ca6 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sat, 23 Oct 2010 20:56:02 +0200 Subject: No need for say_step in 'plugin new' generator --- railties/lib/rails/generators/app_base.rb | 10 ---------- .../rails/generators/rails/plugin_new/plugin_new_generator.rb | 9 +-------- railties/test/generators/plugin_new_generator_test.rb | 7 +++---- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index ad44d9a14e..a355f3b055 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -36,16 +36,6 @@ module Rails :desc => "Show this help message and quit" end - def self.say_step(message) - @step = (@step || 0) + 1 - class_eval <<-METHOD, __FILE__, __LINE__ + 1 - def step_#{@step} - #{"puts" if @step > 1} - say_status "STEP #{@step}", #{message.inspect} - end - METHOD - end - def initialize(*args) @original_wd = Dir.pwd diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 9c0d83cd70..8c4ddc822a 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -102,8 +102,6 @@ end super end - say_step "Creating gem skeleton" - def create_root super end @@ -133,21 +131,16 @@ end build(:test) unless options[:skip_test_unit] end - say_step "Vendoring Rails application at test/dummy" - def create_test_dummy_files + say_status :vendor_app, dummy_path build(:generate_test_dummy) end - say_step "Configuring Rails application" - def change_config_files store_application_definition! build(:test_dummy_config) end - say_step "Removing unneeded files" - def remove_uneeded_rails_files build(:test_dummy_clean) end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 2049d31b18..bf395749e5 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -45,10 +45,9 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/ end - def test_ensure_that_plugin_options_are_not_passed_app_generator - output = run_generator [destination_root, "--skip_gemfile"] - assert_no_file "Gemfile" - assert_match /STEP 2.*create Gemfile/m, output + def test_ensure_that_plugin_options_are_not_passed_to_app_generator + FileUtils.cd(Rails.root) + assert_no_match /It works from file!.*It works_from_file/, run_generator([destination_root, "-m", "lib/template.rb"]) end def test_template_from_dir_pwd -- cgit v1.2.3 From 671d1469c6f70abb7cbd373bb37f18268ed7069c Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 26 Oct 2010 22:22:15 +0200 Subject: Add --full option to 'plugin new' generator, which generates rails engine --- Gemfile | 3 +++ railties/lib/rails/generators/app_base.rb | 5 ++++ .../rails/generators/rails/app/app_generator.rb | 3 --- .../rails/plugin_new/plugin_new_generator.rb | 25 ++++++++++++++++--- .../generators/rails/plugin_new/templates/Gemfile | 5 ++++ .../rails/plugin_new/templates/lib/%name%.rb | 6 +++++ .../rails/plugin_new/templates/lib/%name%.rb.tt | 2 -- .../plugin_new/templates/lib/%name%/engine.rb | 4 ++++ .../plugin_new/templates/rails/application.rb | 8 +++++++ .../rails/plugin_new/templates/test/%name%_test.rb | 7 ++++++ .../plugin_new/templates/test/%name%_test.rb.tt | 7 ------ .../templates/test/integration/navigation_test.rb | 7 ++++++ .../templates/test/support/integration_case.rb | 5 ++++ .../rails/plugin_new/templates/test/test_helper.rb | 16 +++++++++++++ .../test/generators/plugin_new_generator_test.rb | 28 +++++++++++++++++++++- 15 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb delete mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb delete mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb diff --git a/Gemfile b/Gemfile index 66a446a177..202a84ced4 100644 --- a/Gemfile +++ b/Gemfile @@ -25,6 +25,9 @@ gem "memcache-client", ">= 1.8.5" # AM gem "text-format", "~> 1.0.0" +# for 'plugin new --full' generator +gem "capybara" + platforms :mri_18 do gem "system_timer" gem "ruby-debug", ">= 0.10.3" diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index a355f3b055..1b3673e96e 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -26,6 +26,11 @@ module Rails class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, :desc => "Skip Git ignores and keeps" + skip_active_record_desc = "Skip Active Record files" + skip_active_record_desc << " for dummy application" if name == "plugin" + class_option :skip_active_record, :type => :boolean, :aliases => "-O", :default => false, + :desc => skip_active_record_desc + class_option :dev, :type => :boolean, :default => false, :desc => "Setup the #{name} with Gemfile pointing to your Rails checkout" diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 04c2e3738a..6fdc51bd94 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -165,9 +165,6 @@ module Rails class_option :javascript, :type => :string, :aliases => "-j", :default => "prototype", :desc => "Preconfigure for selected javascript library (options: #{JAVASCRIPTS.join('/')})" - class_option :skip_active_record, :type => :boolean, :aliases => "-O", :default => false, - :desc => "Skip Active Record files" - class_option :skip_test_unit, :type => :boolean, :aliases => "-T", :default => false, :desc => "Skip Test::Unit files" diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 8c4ddc822a..d361c490a3 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/hash/slice' require 'rails/generators/app_base' require "rails/generators/rails/app/app_generator" @@ -28,16 +29,26 @@ module Rails end def lib - directory "lib" + template "lib/%name%.rb" + if full? + template "lib/%name%/engine.rb" + end end def test - directory "test" + template "test/test_helper.rb" + template "test/%name%_test.rb" + if full? + template "test/integration/navigation_test.rb" + template "test/support/integration_case.rb" + end end def generate_test_dummy + opts = (options || {}).slice("skip_active_record") + invoke Rails::Generators::AppGenerator, - [ File.expand_path(dummy_path, destination_root) ], {} + [ File.expand_path(dummy_path, destination_root) ], opts end def test_dummy_config @@ -96,6 +107,9 @@ end alias_method :plugin_path, :app_path + class_option :full, :type => :boolean, :default => false, + :desc => "Generate rails engine with integration tests" + def initialize(*args) raise Error, "Options should be given after the plugin name. For details run: rails plugin --help" if args[0].blank? @@ -159,6 +173,10 @@ end protected + def full? + options[:full] + end + def self.banner "rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]" end @@ -183,6 +201,7 @@ end def application_definition @application_definition ||= begin + dummy_application_path = File.expand_path("#{dummy_path}/config/application.rb", destination_root) unless options[:pretend] || !File.exists?(dummy_application_path) contents = File.read(dummy_application_path) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index 53a925d976..7ce44a3d52 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -2,6 +2,11 @@ source "http://rubygems.org" <%= rails_gemfile_entry -%> +<% if full? -%> + gem "capybara", ">= 0.3.9" + gem "sqlite3-ruby", :require => "sqlite3" +<% end -%> + if RUBY_VERSION < '1.9' gem "ruby-debug", ">= 0.10.3" end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb new file mode 100644 index 0000000000..805ba008c3 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb @@ -0,0 +1,6 @@ +<% if full? %> +require "<%= name %>/engine" + +<% end -%> +module <%= camelized %> +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt deleted file mode 100644 index cf77a0b4d3..0000000000 --- a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt +++ /dev/null @@ -1,2 +0,0 @@ -module <%= camelized %> -end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb new file mode 100644 index 0000000000..779bd1cfd3 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb @@ -0,0 +1,4 @@ +module <%= camelized %> + class Engine < Rails::Engine + end +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb index ce655ba7e5..8b68280a5e 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb @@ -1,6 +1,14 @@ require File.expand_path('../boot', __FILE__) +<% unless options[:skip_active_record] -%> require 'rails/all' +<% else -%> +# require "active_record/railtie" +require "action_controller/railtie" +require "action_mailer/railtie" +require "active_resource/railtie" +require "rails/test_unit/railtie" +<% end -%> Bundler.require require "<%= name %>" diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb new file mode 100644 index 0000000000..0a8bbd4aaf --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class <%= camelized %>Test < ActiveSupport::TestCase + test "truth" do + assert_kind_of Module, <%= camelized %> + end +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt deleted file mode 100644 index 0a8bbd4aaf..0000000000 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt +++ /dev/null @@ -1,7 +0,0 @@ -require 'test_helper' - -class <%= camelized %>Test < ActiveSupport::TestCase - test "truth" do - assert_kind_of Module, <%= camelized %> - end -end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb new file mode 100644 index 0000000000..42721899c8 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class NagivationTest < ActiveSupport::IntegrationCase + test "truth" do + assert_kind_of Dummy::Application, Rails.application + end +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb new file mode 100644 index 0000000000..4cfe3f0e71 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb @@ -0,0 +1,5 @@ +# Define a bare test case to use with Capybara +class ActiveSupport::IntegrationCase < ActiveSupport::TestCase + include Capybara + include Rails.application.routes.url_helpers +end \ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb index 791b901593..d821079b91 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb @@ -6,5 +6,21 @@ require "rails/test_help" Rails.backtrace_cleaner.remove_silencers! +<% if full? -%> +ActionMailer::Base.delivery_method = :test +ActionMailer::Base.perform_deliveries = true +ActionMailer::Base.default_url_options[:host] = "test.com" + +# Configure capybara for integration testing +require "capybara/rails" +Capybara.default_driver = :rack_test +Capybara.default_selector = :css + +# Run any available migration from application +ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__) +# and from engine +ActiveRecord::Migrator.migrate File.expand_path("../../db/migrate/", __FILE__) +<% end -%> + # Load support files Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index bf395749e5..f833411e3a 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -41,15 +41,28 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_generating_test_files run_generator assert_file "test/test_helper.rb" - assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/ end + def test_generating_test_files_in_full_mode + run_generator [destination_root, "--full"] + assert_directory "test/support/" + assert_directory "test/integration/" + + assert_file "test/integration/navigation_test.rb", /assert_kind_of Dummy::Application, Rails.application/ + assert_file "test/support/integration_case.rb", /class ActiveSupport::IntegrationCase/ + end + def test_ensure_that_plugin_options_are_not_passed_to_app_generator FileUtils.cd(Rails.root) assert_no_match /It works from file!.*It works_from_file/, run_generator([destination_root, "-m", "lib/template.rb"]) end + def test_ensure_that_skip_active_record_option_is_passed_to_app_generator + run_generator [destination_root, "--skip_active_record"] + assert_no_file "test/dummy/config/database.yml" + end + def test_template_from_dir_pwd FileUtils.cd(Rails.root) assert_match /It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"]) @@ -62,6 +75,19 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_match /1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test` end + def test_ensure_that_tests_works_in_full_mode + run_generator [destination_root, "--full"] + FileUtils.cd destination_root + `bundle install` + assert_match /2 tests, 2 assertions, 0 failures, 0 errors/, `bundle exec rake test` + end + + def test_creating_engine_in_full_mode + run_generator [destination_root, "--full"] + assert_file "lib/bukkits/engine.rb", /module Bukkits\n class Engine < Rails::Engine\n end\nend/ + assert_file "lib/bukkits.rb", /require "bukkits\/engine"/ + end + protected def action(*args, &block) -- cgit v1.2.3 From 46fdb3197d270551da260cfed3dea7928dd15b0f Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 27 Oct 2010 00:16:57 +0200 Subject: Pass more options to test/dummy in 'plugin new' generator --- railties/lib/rails/generators/app_base.rb | 16 +++++++++++++--- railties/lib/rails/generators/rails/app/app_generator.rb | 12 ------------ .../generators/rails/plugin_new/plugin_new_generator.rb | 2 +- railties/test/generators/plugin_new_generator_test.rb | 15 +++++++++++++++ 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 1b3673e96e..0bf5ee86b1 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -8,6 +8,9 @@ require 'uri' module Rails module Generators class AppBase < Base + DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) + JAVASCRIPTS = %w( prototype jquery ) + attr_accessor :rails_template add_shebang_option! @@ -26,10 +29,17 @@ module Rails class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, :desc => "Skip Git ignores and keeps" - skip_active_record_desc = "Skip Active Record files" - skip_active_record_desc << " for dummy application" if name == "plugin" class_option :skip_active_record, :type => :boolean, :aliases => "-O", :default => false, - :desc => skip_active_record_desc + :desc => "Skip Active Record files" + + class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3", + :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})" + + class_option :javascript, :type => :string, :aliases => "-j", :default => "prototype", + :desc => "Preconfigure for selected javascript library (options: #{JAVASCRIPTS.join('/')})" + + class_option :skip_javascript, :type => :boolean, :aliases => "-J", :default => false, + :desc => "Skip javascript files" class_option :dev, :type => :boolean, :default => false, :desc => "Setup the #{name} with Gemfile pointing to your Rails checkout" diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 6fdc51bd94..ef24cf1e05 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -154,23 +154,11 @@ module Rails plugin runner test] class AppGenerator < AppBase - DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) - JAVASCRIPTS = %w( prototype jquery ) - add_shared_options_for "application" - class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3", - :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})" - - class_option :javascript, :type => :string, :aliases => "-j", :default => "prototype", - :desc => "Preconfigure for selected javascript library (options: #{JAVASCRIPTS.join('/')})" - class_option :skip_test_unit, :type => :boolean, :aliases => "-T", :default => false, :desc => "Skip Test::Unit files" - class_option :skip_javascript, :type => :boolean, :aliases => "-J", :default => false, - :desc => "Skip javascript files" - # Add bin/rails options class_option :version, :type => :boolean, :aliases => "-v", :group => :rails, :desc => "Show Rails version number and quit" diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index d361c490a3..b514554da7 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -45,7 +45,7 @@ module Rails end def generate_test_dummy - opts = (options || {}).slice("skip_active_record") + opts = (options || {}).slice(:skip_active_record, :skip_javascript, :database, :javascript) invoke Rails::Generators::AppGenerator, [ File.expand_path(dummy_path, destination_root) ], opts diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index f833411e3a..53e1dd6708 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -63,6 +63,21 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_no_file "test/dummy/config/database.yml" end + def test_ensure_that_database_option_is_passed_to_app_generator + run_generator [destination_root, "--database", "postgresql"] + assert_file "test/dummy/config/database.yml", /postgres/ + end + + def test_ensure_that_javascript_option_is_passed_to_app_generator + run_generator [destination_root, "--javascript", "jquery"] + assert_file "test/dummy/public/javascripts/jquery.js" + end + + def test_ensure_that_skip_javascript_option_is_passed_to_app_generator + run_generator [destination_root, "--skip_javascript"] + assert_no_file "test/dummy/public/javascripts/prototype.js" + end + def test_template_from_dir_pwd FileUtils.cd(Rails.root) assert_match /It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"]) -- cgit v1.2.3 From 013fc0a418379d6f62bbd1f86d2b5bd674927fe7 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 27 Oct 2010 00:31:29 +0200 Subject: No need to require 'app_base', it's required in app_generator --- railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index b514554da7..e464279af6 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -1,5 +1,4 @@ require 'active_support/core_ext/hash/slice' -require 'rails/generators/app_base' require "rails/generators/rails/app/app_generator" module Rails -- cgit v1.2.3 From 489b279fc499f135df48556554739c19d316df0a Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 28 Oct 2010 03:00:42 +0200 Subject: Don't be verbose while creating dummy application in plugin new generator --- Gemfile | 2 ++ .../generators/rails/plugin_new/plugin_new_generator.rb | 16 +++++++++++++--- railties/test/generators/plugin_new_generator_test.rb | 4 ++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 202a84ced4..a23d482703 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,8 @@ else gem "arel", :git => "git://github.com/rails/arel.git" end +gem "thor", :git => "git://github.com/wycats/thor.git" + gem "rack", :git => "git://github.com/rack/rack.git" gem "rails", :path => File.dirname(__FILE__) diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index e464279af6..7b202344ee 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -146,16 +146,22 @@ end def create_test_dummy_files say_status :vendor_app, dummy_path - build(:generate_test_dummy) + mute do + build(:generate_test_dummy) + end end def change_config_files store_application_definition! - build(:test_dummy_config) + mute do + build(:test_dummy_config) + end end def remove_uneeded_rails_files - build(:test_dummy_clean) + mute do + build(:test_dummy_clean) + end end def finish_template @@ -219,6 +225,10 @@ end builder.send(name) if builder.respond_to?(name) end end + + def mute(&block) + shell.mute(&block) + end end end end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 53e1dd6708..985ef088e5 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -103,6 +103,10 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "lib/bukkits.rb", /require "bukkits\/engine"/ end + def test_being_quiet_while_creating_dummy_application + assert_no_match /create\s+config\/application.rb/, run_generator + end + protected def action(*args, &block) -- cgit v1.2.3 From 9e86767bb88f45db0f9aef42b1bea1177cba8e53 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 28 Oct 2010 17:22:41 +0200 Subject: Do not create additional newline --- railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb index 805ba008c3..2d3bdc510c 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb @@ -1,4 +1,4 @@ -<% if full? %> +<% if full? -%> require "<%= name %>/engine" <% end -%> -- cgit v1.2.3 From cfbe5958311f21397c98657c3370d03dcf720fe1 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 28 Oct 2010 18:00:52 +0200 Subject: Use application's generators defaults as engine defaults to not force users to manually set it --- activerecord/lib/active_record/railtie.rb | 2 +- railties/lib/rails/engine/configuration.rb | 1 + railties/test/railties/engine_test.rb | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 868fd6c3ff..dfe255ad7c 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -14,7 +14,7 @@ module ActiveRecord config.active_record = ActiveSupport::OrderedOptions.new config.app_generators.orm :active_record, :migration => true, - :timestamps => true + :timestamps => true config.app_middleware.insert_after "::ActionDispatch::Callbacks", "ActiveRecord::QueryCache" diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 7a07dcad7d..5607628d96 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -10,6 +10,7 @@ module Rails def initialize(root=nil) super() @root = root + @generators = app_generators end # Returns the middleware stack for the engine. diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 4b52260ecc..3509f964eb 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -685,5 +685,22 @@ module RailtiesTest assert_equal :haml , generators[:template_engine] assert_equal :rspec , generators[:test_framework] end + + test "engine should get default generators with ability to overwrite them" do + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + class Engine < ::Rails::Engine + config.generators.test_framework :rspec + end + end + RUBY + + boot_rails + require "#{rails_root}/config/environment" + + generators = Bukkits::Engine.config.generators.options[:rails] + assert_equal :active_record, generators[:orm] + assert_equal :rspec , generators[:test_framework] + end end end -- cgit v1.2.3 From 5071b727b438f1ca6be502c906f5af751abb0229 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 28 Oct 2010 19:43:21 +0200 Subject: Added Hash#deep_dup function which performs deep duplication on given hash --- activesupport/lib/active_support/core_ext/hash.rb | 1 + .../lib/active_support/core_ext/hash/deep_dup.rb | 11 +++++++++++ activesupport/test/core_ext/hash_ext_test.rb | 15 +++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 activesupport/lib/active_support/core_ext/hash/deep_dup.rb diff --git a/activesupport/lib/active_support/core_ext/hash.rb b/activesupport/lib/active_support/core_ext/hash.rb index 501483498d..fd1cda991e 100644 --- a/activesupport/lib/active_support/core_ext/hash.rb +++ b/activesupport/lib/active_support/core_ext/hash.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/hash/conversions' require 'active_support/core_ext/hash/deep_merge' +require 'active_support/core_ext/hash/deep_dup' require 'active_support/core_ext/hash/diff' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/indifferent_access' diff --git a/activesupport/lib/active_support/core_ext/hash/deep_dup.rb b/activesupport/lib/active_support/core_ext/hash/deep_dup.rb new file mode 100644 index 0000000000..447142605c --- /dev/null +++ b/activesupport/lib/active_support/core_ext/hash/deep_dup.rb @@ -0,0 +1,11 @@ +class Hash + # Returns a deep copy of hash. + def deep_dup + duplicate = self.dup + duplicate.each_pair do |k,v| + tv = duplicate[k] + duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v + end + duplicate + end +end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 545fed2684..bfcfddad47 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -316,6 +316,21 @@ class HashExtTest < Test::Unit::TestCase assert_equal expected, hash_1 end + def test_deep_dup + hash = { :a => { :b => 'b' } } + dup = hash.deep_dup + dup[:a][:c] = 'c' + assert_equal nil, hash[:a][:c] + assert_equal 'c', dup[:a][:c] + end + + def test_deep_dup_initialize + zero_hash = Hash.new 0 + hash = { :a => zero_hash } + dup = hash.deep_dup + assert_equal 0, dup[:a][44] + end + def test_store_on_indifferent_access hash = HashWithIndifferentAccess.new hash.store(:test1, 1) -- cgit v1.2.3 From a5311ee86bffad3f0bce00babd1ff5d78ec85618 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 28 Oct 2010 20:25:20 +0200 Subject: Make deep copy of application generators on engine initialization. Otherwise nested hashes will be same objects for both application and engine, which will result in overwriting each others values on changes. --- railties/lib/rails/configuration.rb | 8 ++++++++ railties/lib/rails/engine/configuration.rb | 2 +- railties/test/railties/engine_test.rb | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 8369795e71..66fab0a760 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -1,5 +1,6 @@ require 'active_support/deprecation' require 'active_support/ordered_options' +require 'active_support/core_ext/hash/deep_dup' require 'rails/paths' require 'rails/rack' @@ -51,6 +52,13 @@ module Rails @colorize_logging = true end + def initialize_copy(source) + @aliases = @aliases.deep_dup + @options = @options.deep_dup + @fallbacks = @fallbacks.deep_dup + @templates = @templates.dup + end + def method_missing(method, *args) method = method.to_s.sub(/=$/, '').to_sym diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 5607628d96..4f458b0aee 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -10,7 +10,7 @@ module Rails def initialize(root=nil) super() @root = root - @generators = app_generators + @generators = app_generators.dup end # Returns the middleware stack for the engine. diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 3509f964eb..822be24ef1 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -701,6 +701,9 @@ module RailtiesTest generators = Bukkits::Engine.config.generators.options[:rails] assert_equal :active_record, generators[:orm] assert_equal :rspec , generators[:test_framework] + + app_generators = Rails.application.config.generators.options[:rails] + assert_equal :test_unit , app_generators[:test_framework] end end end -- cgit v1.2.3 From 9cb9713eebd786bd5113470af67b6c81bb57986e Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Fri, 29 Oct 2010 20:06:48 +0200 Subject: Refactor app and plugin generators to use new Thor API --- railties/lib/rails/generators/rails/app/app_generator.rb | 12 ++---------- .../generators/rails/plugin_new/plugin_new_generator.rb | 12 ++---------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index ef24cf1e05..e2d2ae71ba 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -177,9 +177,7 @@ module Rails end end - def create_root - super - end + public_task :create_root def create_root_files build(:readme) @@ -258,13 +256,7 @@ module Rails build(:leftovers) end - def apply_rails_template - super - end - - def bundle_if_dev_or_edge - super - end + public_task :apply_rails_template, :bundle_if_dev_or_edge protected diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 7b202344ee..ddc801a0ae 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -115,9 +115,7 @@ end super end - def create_root - super - end + public_task :create_root def create_root_files build(:readme) @@ -168,13 +166,7 @@ end build(:leftovers) end - def apply_rails_template - super - end - - def bundle_if_dev_or_edge - super - end + public_task :apply_rails_template, :bundle_if_dev_or_edge protected -- cgit v1.2.3 From 4d108cb33d818949e7682076ad662c99168093e4 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 2 Nov 2010 12:56:00 +0100 Subject: We don't need to configure ActionMailer in plugin's test helper, it's configured by dummy app --- .../rails/generators/rails/plugin_new/templates/test/test_helper.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb index d821079b91..4562c88a54 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb @@ -7,10 +7,6 @@ require "rails/test_help" Rails.backtrace_cleaner.remove_silencers! <% if full? -%> -ActionMailer::Base.delivery_method = :test -ActionMailer::Base.perform_deliveries = true -ActionMailer::Base.default_url_options[:host] = "test.com" - # Configure capybara for integration testing require "capybara/rails" Capybara.default_driver = :rack_test -- cgit v1.2.3 From 57fae9b2c7d193ec16baf38a8797588fb466db49 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 2 Nov 2010 14:05:11 +0100 Subject: Use rails integration tests by default in 'plugin new' generator --- Gemfile | 3 --- .../rails/generators/rails/plugin_new/plugin_new_generator.rb | 1 - .../lib/rails/generators/rails/plugin_new/templates/Gemfile | 1 - .../plugin_new/templates/test/integration/navigation_test.rb | 10 +++++++--- .../plugin_new/templates/test/support/integration_case.rb | 5 ----- .../generators/rails/plugin_new/templates/test/test_helper.rb | 5 ----- railties/test/generators/plugin_new_generator_test.rb | 4 +--- 7 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb diff --git a/Gemfile b/Gemfile index a23d482703..ac9c63790c 100644 --- a/Gemfile +++ b/Gemfile @@ -27,9 +27,6 @@ gem "memcache-client", ">= 1.8.5" # AM gem "text-format", "~> 1.0.0" -# for 'plugin new --full' generator -gem "capybara" - platforms :mri_18 do gem "system_timer" gem "ruby-debug", ">= 0.10.3" diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index ddc801a0ae..ef3ded424d 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -39,7 +39,6 @@ module Rails template "test/%name%_test.rb" if full? template "test/integration/navigation_test.rb" - template "test/support/integration_case.rb" end end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index 7ce44a3d52..928ea8b9c4 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -3,7 +3,6 @@ source "http://rubygems.org" <%= rails_gemfile_entry -%> <% if full? -%> - gem "capybara", ">= 0.3.9" gem "sqlite3-ruby", :require => "sqlite3" <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb index 42721899c8..d06fe7cbd0 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb @@ -1,7 +1,11 @@ require 'test_helper' -class NagivationTest < ActiveSupport::IntegrationCase - test "truth" do - assert_kind_of Dummy::Application, Rails.application +class NavigationTest < ActionDispatch::IntegrationTest + fixtures :all + + # Replace this with your real tests. + test "the truth" do + assert true end end + diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb deleted file mode 100644 index 4cfe3f0e71..0000000000 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Define a bare test case to use with Capybara -class ActiveSupport::IntegrationCase < ActiveSupport::TestCase - include Capybara - include Rails.application.routes.url_helpers -end \ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb index 4562c88a54..b42e45d544 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb @@ -7,11 +7,6 @@ require "rails/test_help" Rails.backtrace_cleaner.remove_silencers! <% if full? -%> -# Configure capybara for integration testing -require "capybara/rails" -Capybara.default_driver = :rack_test -Capybara.default_selector = :css - # Run any available migration from application ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__) # and from engine diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 985ef088e5..aebd954215 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -46,11 +46,9 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_generating_test_files_in_full_mode run_generator [destination_root, "--full"] - assert_directory "test/support/" assert_directory "test/integration/" - assert_file "test/integration/navigation_test.rb", /assert_kind_of Dummy::Application, Rails.application/ - assert_file "test/support/integration_case.rb", /class ActiveSupport::IntegrationCase/ + assert_file "test/integration/navigation_test.rb", /ActionDispatch::IntegrationTest/ end def test_ensure_that_plugin_options_are_not_passed_to_app_generator -- cgit v1.2.3 From b6497d3b5a84ca5e7e15700419ddf44c096c57a2 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 2 Nov 2010 14:07:58 +0100 Subject: Skip active record properly in 'plugin new' generator --- .../lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb | 2 +- railties/test/generators/plugin_new_generator_test.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb index b42e45d544..dbcaf6b92f 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb @@ -6,7 +6,7 @@ require "rails/test_help" Rails.backtrace_cleaner.remove_silencers! -<% if full? -%> +<% if full? && !options[:skip_active_record] -%> # Run any available migration from application ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__) # and from engine diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index aebd954215..20c0d0a9bf 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -59,6 +59,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_ensure_that_skip_active_record_option_is_passed_to_app_generator run_generator [destination_root, "--skip_active_record"] assert_no_file "test/dummy/config/database.yml" + assert_no_match /ActiveRecord/, File.read(File.join(destination_root, "test/test_helper.rb")) end def test_ensure_that_database_option_is_passed_to_app_generator -- cgit v1.2.3 From 2133495b8cdcb40a68a03aa786c4353031abe49e Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 2 Nov 2010 14:23:45 +0100 Subject: Properly handle other databases in 'plugin new' generator --- railties/lib/rails/generators/app_base.rb | 27 ++++++++++++++++++++++ .../rails/generators/rails/app/app_generator.rb | 18 --------------- .../rails/generators/rails/app/templates/Gemfile | 4 +--- .../generators/rails/plugin_new/templates/Gemfile | 2 +- railties/test/generators/app_generator_test.rb | 5 ---- .../test/generators/plugin_new_generator_test.rb | 17 ++++++++++++++ railties/test/generators/shared_generator_tests.rb | 5 ++++ 7 files changed, 51 insertions(+), 27 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 0bf5ee86b1..b7a4b16f10 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -108,6 +108,15 @@ module Rails end end + def database_gemfile_entry + entry = "" + unless options[:skip_active_record] + entry = "gem '#{gem_for_database}'" + entry << ", :require => '#{require_for_database}'" if require_for_database + end + entry + end + def rails_gemfile_entry if options.dev? <<-GEMFILE @@ -133,6 +142,24 @@ gem 'rails', '#{Rails::VERSION::STRING}' end end + def gem_for_database + # %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) + case options[:database] + when "oracle" then "ruby-oci8" + when "postgresql" then "pg" + when "sqlite3" then "sqlite3-ruby" + when "frontbase" then "ruby-frontbase" + when "mysql" then "mysql2" + else options[:database] + end + end + + def require_for_database + case options[:database] + when "sqlite3" then "sqlite3" + end + end + def bundle_if_dev_or_edge bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') run "#{bundle_command} install" if dev_or_edge? diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index e2d2ae71ba..7a6a7972d2 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -306,24 +306,6 @@ module Rails ActiveSupport::SecureRandom.hex(64) end - def gem_for_database - # %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) - case options[:database] - when "oracle" then "ruby-oci8" - when "postgresql" then "pg" - when "sqlite3" then "sqlite3-ruby" - when "frontbase" then "ruby-frontbase" - when "mysql" then "mysql2" - else options[:database] - end - end - - def require_for_database - case options[:database] - when "sqlite3" then "sqlite3" - end - end - def mysql_socket @mysql_socket ||= [ "/tmp/mysql.sock", # default diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 4a37f675ad..86b9e8f40c 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -2,9 +2,7 @@ source 'http://rubygems.org' <%= rails_gemfile_entry -%> -<% unless options[:skip_active_record] -%> -gem '<%= gem_for_database %>'<% if require_for_database %>, :require => '<%= require_for_database %>'<% end %> -<% end -%> +<%= database_gemfile_entry -%> # Use unicorn as the web server # gem 'unicorn' diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index 928ea8b9c4..29900c93dc 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -3,7 +3,7 @@ source "http://rubygems.org" <%= rails_gemfile_entry -%> <% if full? -%> - gem "sqlite3-ruby", :require => "sqlite3" +<%= database_gemfile_entry -%> <% end -%> if RUBY_VERSION < '1.9' diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 42a49eb03c..ddd8272db6 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -53,11 +53,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_file "public/stylesheets/application.css" end - def test_invalid_database_option_raises_an_error - content = capture(:stderr){ run_generator([destination_root, "-d", "unknown"]) } - assert_match /Invalid value for \-\-database option/, content - end - def test_invalid_application_name_raises_an_error content = capture(:stderr){ run_generator [File.join(destination_root, "43-things")] } assert_equal "Invalid application name 43-things. Please give a name which does not start with numbers.\n", content diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 20c0d0a9bf..6b7095ba78 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -56,6 +56,23 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_no_match /It works from file!.*It works_from_file/, run_generator([destination_root, "-m", "lib/template.rb"]) end + def test_database_entry_is_assed_by_default_in_full_mode + run_generator([destination_root, "--full"]) + assert_file "test/dummy/config/database.yml", /sqlite/ + assert_file "Gemfile", /^gem\s+["']sqlite3-ruby["'],\s+:require\s+=>\s+["']sqlite3["']$/ + end + + def test_config_another_database + run_generator([destination_root, "-d", "mysql", "--full"]) + assert_file "test/dummy/config/database.yml", /mysql/ + assert_file "Gemfile", /^gem\s+["']mysql2["']$/ + end + + def test_active_record_is_removed_from_frameworks_if_skip_active_record_is_given + run_generator [destination_root, "--skip-active-record"] + assert_file "test/dummy/config/application.rb", /#\s+require\s+["']active_record\/railtie["']/ + end + def test_ensure_that_skip_active_record_option_is_passed_to_app_generator run_generator [destination_root, "--skip_active_record"] assert_no_file "test/dummy/config/database.yml" diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 71cde6785c..054a3d008a 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -30,6 +30,11 @@ module SharedGeneratorTests default_files.each{ |path| assert_no_file path } end + def test_invalid_database_option_raises_an_error + content = capture(:stderr){ run_generator([destination_root, "-d", "unknown"]) } + assert_match /Invalid value for \-\-database option/, content + end + def test_options_before_application_name_raises_an_error content = capture(:stderr){ run_generator(["--pretend", destination_root]) } assert_match /Options should be given after the \w+ name. For details run: rails( plugin)? --help\n/, content -- cgit v1.2.3 From fadad11f9056a0166ee490a5eb0a4d9a01120d38 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 2 Nov 2010 14:52:08 +0100 Subject: Properly skip test unit in 'plugin new' generator --- railties/lib/rails/generators/app_base.rb | 3 +++ .../rails/generators/rails/app/app_generator.rb | 3 --- .../rails/plugin_new/plugin_new_generator.rb | 28 +++++++++------------- .../generators/rails/plugin_new/templates/Rakefile | 4 +++- railties/test/generators/app_generator_test.rb | 5 ---- railties/test/generators/shared_generator_tests.rb | 5 ++++ 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index b7a4b16f10..f5c626553c 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -47,6 +47,9 @@ module Rails class_option :edge, :type => :boolean, :default => false, :desc => "Setup the #{name} with Gemfile pointing to Rails repository" + class_option :skip_test_unit, :type => :boolean, :aliases => "-T", :default => false, + :desc => "Skip Test::Unit files" + class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, :desc => "Show this help message and quit" end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 7a6a7972d2..ef1eb8d237 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -156,9 +156,6 @@ module Rails class AppGenerator < AppBase add_shared_options_for "application" - class_option :skip_test_unit, :type => :boolean, :aliases => "-T", :default => false, - :desc => "Skip Test::Unit files" - # Add bin/rails options class_option :version, :type => :boolean, :aliases => "-v", :group => :rails, :desc => "Show Rails version number and quit" diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index ef3ded424d..29a92c9388 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -142,23 +142,8 @@ end end def create_test_dummy_files - say_status :vendor_app, dummy_path - mute do - build(:generate_test_dummy) - end - end - - def change_config_files - store_application_definition! - mute do - build(:test_dummy_config) - end - end - - def remove_uneeded_rails_files - mute do - build(:test_dummy_clean) - end + return if options[:skip_test_unit] + create_test_dummy(dummy_path) end def finish_template @@ -168,6 +153,15 @@ end public_task :apply_rails_template, :bundle_if_dev_or_edge protected + def create_test_dummy(dummy_path) + say_status :vendor_app, dummy_path + mute do + build(:generate_test_dummy) + store_application_definition! + build(:test_dummy_config) + build(:test_dummy_clean) + end + end def full? options[:full] diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile index 3c53b677a0..dd7c11622d 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile @@ -9,9 +9,11 @@ end require 'rake' require 'rake/rdoctask' +<% unless options[:skip_test_unit] -%> <%= rakefile_test_tasks %> -task :default => :<%= test_path %> +task :default => :test +<% end -%> Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index ddd8272db6..6b2026ad0c 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -138,11 +138,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "test" end - def test_test_unit_is_skipped_if_required - run_generator [destination_root, "--skip-test-unit"] - assert_no_file "test" - end - def test_javascript_is_skipped_if_required run_generator [destination_root, "--skip-javascript"] assert_file "config/application.rb", /^\s+config\.action_view\.javascript_expansions\[:defaults\]\s+=\s+%w\(\)/ diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 054a3d008a..d117656fbd 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -35,6 +35,11 @@ module SharedGeneratorTests assert_match /Invalid value for \-\-database option/, content end + def test_test_unit_is_skipped_if_required + run_generator [destination_root, "--skip-test-unit"] + assert_no_file "test" + end + def test_options_before_application_name_raises_an_error content = capture(:stderr){ run_generator(["--pretend", destination_root]) } assert_match /Options should be given after the \w+ name. For details run: rails( plugin)? --help\n/, content -- cgit v1.2.3 From f9e33fc09a6731ad56ff8cfe24b49532ed65039c Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 2 Nov 2010 15:13:10 +0100 Subject: create_dummy_app method that allows to easily create dummy application from template --- .../rails/plugin_new/plugin_new_generator.rb | 61 +++++++++++----------- .../generators/rails/plugin_new/templates/Rakefile | 6 --- .../rails/plugin_new/templates/script/rails.tt | 2 +- .../fixtures/lib/create_test_dummy_template.rb | 1 + .../fixtures/lib/plugin_builders/spec_builder.rb | 14 +++-- .../test/generators/plugin_new_generator_test.rb | 9 +++- 6 files changed, 51 insertions(+), 42 deletions(-) create mode 100644 railties/test/fixtures/lib/create_test_dummy_template.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 29a92c9388..eac4f76510 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -37,13 +37,19 @@ module Rails def test template "test/test_helper.rb" template "test/%name%_test.rb" + append_file "Rakefile", <<-EOF +#{rakefile_test_tasks} + +task :default => :test + EOF if full? template "test/integration/navigation_test.rb" end end - def generate_test_dummy + def generate_test_dummy(force = false) opts = (options || {}).slice(:skip_active_record, :skip_javascript, :database, :javascript) + opts[:force] = force invoke Rails::Generators::AppGenerator, [ File.expand_path(dummy_path, destination_root) ], opts @@ -70,33 +76,12 @@ module Rails end end - def script - directory "script" do |content| + def script(force = false) + directory "script", :force => force do |content| "#{shebang}\n" + content end chmod "script", 0755, :verbose => false end - - def rakefile_test_tasks - <<-RUBY -require 'rake/testtask' - -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.libs << 'test' - t.pattern = 'test/**/*_test.rb' - t.verbose = false -end - RUBY - end - - def dummy_path - "#{test_path}/dummy" - end - - def test_path - "test" - end end module Generators @@ -143,7 +128,7 @@ end def create_test_dummy_files return if options[:skip_test_unit] - create_test_dummy(dummy_path) + create_dummy_app end def finish_template @@ -153,13 +138,17 @@ end public_task :apply_rails_template, :bundle_if_dev_or_edge protected - def create_test_dummy(dummy_path) + def create_dummy_app(path = nil) + dummy_path(path) if path + say_status :vendor_app, dummy_path mute do build(:generate_test_dummy) store_application_definition! build(:test_dummy_config) build(:test_dummy_clean) + # ensure that script/rails has proper dummy_path + build(:script, true) end end @@ -205,10 +194,22 @@ end defined?(::PluginBuilder) ? ::PluginBuilder : Rails::PluginBuilder end - [:test_path, :dummy_path, :rakefile_test_tasks].each do |name| - define_method name do - builder.send(name) if builder.respond_to?(name) - end + def rakefile_test_tasks + <<-RUBY +require 'rake/testtask' + +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.verbose = false +end + RUBY + end + + def dummy_path(path = nil) + @dummy_path = path if path + @dummy_path || "test/dummy" end def mute(&block) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile index dd7c11622d..88f50f9f04 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile @@ -9,12 +9,6 @@ end require 'rake' require 'rake/rdoctask' -<% unless options[:skip_test_unit] -%> -<%= rakefile_test_tasks %> - -task :default => :test -<% end -%> - Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' rdoc.title = '<%= camelized %>' diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt b/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt index 91d9cf079d..ebd5a77dd5 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +++ b/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt @@ -2,4 +2,4 @@ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. ENGINE_PATH = File.expand_path('../..', __FILE__) -load File.expand_path('../../<%= test_path %>/dummy/script/rails', __FILE__) +load File.expand_path('../../<%= dummy_path %>/script/rails', __FILE__) diff --git a/railties/test/fixtures/lib/create_test_dummy_template.rb b/railties/test/fixtures/lib/create_test_dummy_template.rb new file mode 100644 index 0000000000..e4378bbd1a --- /dev/null +++ b/railties/test/fixtures/lib/create_test_dummy_template.rb @@ -0,0 +1 @@ +create_dummy_app("spec/dummy") diff --git a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb index bdaa1fb8e1..aa18c7ddaa 100644 --- a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb +++ b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb @@ -1,13 +1,19 @@ class PluginBuilder < Rails::PluginBuilder def test create_file "spec/spec_helper.rb" + append_file "Rakefile", <<-EOF +# spec tasks in rakefile + +task :default => :spec + EOF end - def test_path - "spec" + def generate_test_dummy + dummy_path("spec/dummy") + super end - def rakefile_test_tasks - "# spec tasks in rakefile" + def skip_test_unit? + true end end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 6b7095ba78..f7f4f0261f 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -56,6 +56,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_no_match /It works from file!.*It works_from_file/, run_generator([destination_root, "-m", "lib/template.rb"]) end + def test_ensure_that_test_dummy_can_be_generated_from_a_template + FileUtils.cd(Rails.root) + run_generator([destination_root, "-m", "lib/create_test_dummy_template.rb", "--skip-test-unit"]) + assert_file "spec/dummy" + assert_no_file "test" + end + def test_database_entry_is_assed_by_default_in_full_mode run_generator([destination_root, "--full"]) assert_file "test/dummy/config/database.yml", /sqlite/ @@ -143,9 +150,9 @@ class CustomPluginGeneratorTest < Rails::Generators::TestCase FileUtils.cd(destination_root) run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/spec_builder.rb"]) assert_file 'spec/spec_helper.rb' + assert_file 'spec/dummy' assert_file 'Rakefile', /task :default => :spec/ assert_file 'Rakefile', /# spec tasks in rakefile/ - assert_file 'spec/dummy' assert_file 'script/rails', %r{spec/dummy} end -- cgit v1.2.3 From c159b501b0743928bda6a9d0609c263e50691676 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 2 Nov 2010 15:44:07 +0100 Subject: Add example rake task to 'plugin new' generator --- .../lib/rails/generators/rails/plugin_new/plugin_new_generator.rb | 1 + .../generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake | 4 ++++ railties/test/generators/plugin_new_generator_test.rb | 1 + 3 files changed, 6 insertions(+) create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index eac4f76510..b8408a0f9b 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -29,6 +29,7 @@ module Rails def lib template "lib/%name%.rb" + template "lib/tasks/%name%_tasks.rake" if full? template "lib/%name%/engine.rb" end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake b/railties/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake new file mode 100644 index 0000000000..7121f5ae23 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake @@ -0,0 +1,4 @@ +# desc "Explaining what the task does" +# task :<%= name %> do +# # Task goes here +# end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index f7f4f0261f..c66b0024e5 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -11,6 +11,7 @@ DEFAULT_PLUGIN_FILES = %w( MIT-LICENSE lib lib/bukkits.rb + lib/tasks/bukkits_tasks.rake script/rails test/bukkits_test.rb test/test_helper.rb -- cgit v1.2.3 From cbe391b517f55caad8cbefa6f864289d76fab653 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 2 Nov 2010 16:34:07 +0100 Subject: Add --mountable option to 'plugin new' generator which generates full mountable application (engine) --- .../rails/plugin_new/plugin_new_generator.rb | 28 +++++++++++++++++++--- .../%name%/application_controller.rb.tt | 4 ++++ .../app/helpers/%name%/application_helper.rb.tt | 4 ++++ .../rails/plugin_new/templates/config/routes.rb | 3 +++ .../plugin_new/templates/lib/%name%/engine.rb | 3 +++ .../rails/plugin_new/templates/rails/routes.rb | 4 ++++ .../test/generators/plugin_new_generator_test.rb | 9 +++++++ 7 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/config/routes.rb create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index b8408a0f9b..d4706063f3 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -7,6 +7,10 @@ module Rails template "Rakefile" end + def app + directory "app" if options[:mountable] + end + def readme copy_file "README.rdoc" end @@ -35,6 +39,10 @@ module Rails end end + def config + template "config/routes.rb" if mountable? + end + def test template "test/test_helper.rb" template "test/%name%_test.rb" @@ -59,6 +67,9 @@ task :default => :test def test_dummy_config template "rails/boot.rb", "#{dummy_path}/config/boot.rb", :force => true template "rails/application.rb", "#{dummy_path}/config/application.rb", :force => true + if mountable? + template "rails/routes.rb", "#{dummy_path}/config/routes.rb", :force => true + end end def test_dummy_clean @@ -91,8 +102,11 @@ task :default => :test alias_method :plugin_path, :app_path - class_option :full, :type => :boolean, :default => false, - :desc => "Generate rails engine with integration tests" + class_option :full, :type => :boolean, :default => false, + :desc => "Generate rails engine with integration tests" + + class_option :mountable, :type => :boolean, :default => false, + :desc => "Generate mountable isolated application" def initialize(*args) raise Error, "Options should be given after the plugin name. For details run: rails plugin --help" if args[0].blank? @@ -111,6 +125,10 @@ task :default => :test build(:gemfile) unless options[:skip_gemfile] end + def create_app_files + build(:app) + end + def create_config_files build(:config) end @@ -154,7 +172,11 @@ task :default => :test end def full? - options[:full] + options[:full] || options[:mountable] + end + + def mountable? + options[:mountable] end def self.banner diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt new file mode 100644 index 0000000000..f225bc9f7f --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt @@ -0,0 +1,4 @@ +module <%= camelized %> + class ApplicationController < ActiveController::Base + end +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt new file mode 100644 index 0000000000..40ae9f52c2 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt @@ -0,0 +1,4 @@ +module <%= camelized %> + module ApplicationHelper + end +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/config/routes.rb b/railties/lib/rails/generators/rails/plugin_new/templates/config/routes.rb new file mode 100644 index 0000000000..42ddf380d8 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/config/routes.rb @@ -0,0 +1,3 @@ +<%= camelized %>::Engine.routes.draw do + +end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb index 779bd1cfd3..9600ee0c3f 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb @@ -1,4 +1,7 @@ module <%= camelized %> class Engine < Rails::Engine +<% if mountable? -%> + isolate_namespace <%= camelized %> +<% end -%> end end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb new file mode 100644 index 0000000000..730ee31c3d --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb @@ -0,0 +1,4 @@ +Rails.application.routes.draw do + + mount <%= camelized %>::Engine => "/<%= name %>" +end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index c66b0024e5..a59013b061 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -131,6 +131,15 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_no_match /create\s+config\/application.rb/, run_generator end + def test_create_mountable_application_with_mountable_option + run_generator [destination_root, "--mountable"] + assert_file "config/routes.rb", /Bukkits::Engine.routes.draw do/ + assert_file "lib/bukkits/engine.rb", /isolate_namespace Bukkits/ + assert_file "test/dummy/config/routes.rb", /mount Bukkits::Engine => "\/bukkits"/ + assert_file "app/controllers/bukkits/application_controller.rb", /module Bukkits\n class ApplicationController < ActiveController::Base/ + assert_file "app/helpers/bukkits/application_helper.rb", /module Bukkits\n module ApplicationHelper/ + end + protected def action(*args, &block) -- cgit v1.2.3 From bb9c58eb4aa637fa75c69c705a9918d6322ff834 Mon Sep 17 00:00:00 2001 From: Jeff Kreeftmeijer Date: Mon, 11 Oct 2010 20:39:12 +0200 Subject: Make sure capture's output gets html_escaped [#5545 state:resolved] Also remove a duplicate test_link_to_unless assertion and add .html_safe to the remaining one. Signed-off-by: Santiago Pastorino --- actionpack/lib/action_view/helpers/capture_helper.rb | 3 ++- actionpack/test/template/capture_helper_test.rb | 5 +++++ actionpack/test/template/url_helper_test.rb | 7 +------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 0401e6a09b..2c805c8ecf 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/string/output_safety' module ActionView # = Action View Capture Helper @@ -38,7 +39,7 @@ module ActionView value = nil buffer = with_output_buffer { value = yield(*args) } if string = buffer.presence || value and string.is_a?(String) - string + html_escape string end end diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb index 8f81076299..25da17bde9 100644 --- a/actionpack/test/template/capture_helper_test.rb +++ b/actionpack/test/template/capture_helper_test.rb @@ -28,6 +28,11 @@ class CaptureHelperTest < ActionView::TestCase assert_nil @av.capture { 1 } end + def test_capture_escapes_html + string = @av.capture { 'foobar' } + assert_equal '<strong>foo</strong><em>bar</em>', string + end + def test_content_for assert ! content_for?(:title) content_for :title, 'title' diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index bc2548e06c..4a8cea36d4 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -263,12 +263,7 @@ class UrlHelperTest < ActiveSupport::TestCase assert_equal "Showing", link_to_unless(true, "Showing", url_hash) { |name| - "#{name}" - } - - assert_equal "Showing", - link_to_unless(true, "Showing", url_hash) { |name| - "#{name}" + "#{name}".html_safe } assert_equal "test", -- cgit v1.2.3 From 72d12d94559f7c124fa2ec88eb668ad2948c02f4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 2 Nov 2010 20:02:13 -0200 Subject: Call as ERB::Util.html_escape since is not the module is not included here --- actionpack/lib/action_view/helpers/capture_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 2c805c8ecf..c88bd1efd5 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -39,7 +39,7 @@ module ActionView value = nil buffer = with_output_buffer { value = yield(*args) } if string = buffer.presence || value and string.is_a?(String) - html_escape string + ERB::Util.html_escape string end end -- cgit v1.2.3 From 3c7215bdce30aaaa6b86f5ec905c981346e170eb Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 2 Nov 2010 20:02:55 -0200 Subject: Test that capture doesn't escape twice --- actionpack/test/template/capture_helper_test.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb index 25da17bde9..03050485fa 100644 --- a/actionpack/test/template/capture_helper_test.rb +++ b/actionpack/test/template/capture_helper_test.rb @@ -29,8 +29,13 @@ class CaptureHelperTest < ActionView::TestCase end def test_capture_escapes_html - string = @av.capture { 'foobar' } - assert_equal '<strong>foo</strong><em>bar</em>', string + string = @av.capture { 'bar' } + assert_equal '<em>bar</em>', string + end + + def test_capture_doesnt_escape_twice + string = @av.capture { '<em>bar</em>'.html_safe } + assert_equal '<em>bar</em>', string end def test_content_for -- cgit v1.2.3 From c4d977fbbc31b0a6c7557846f9fe01e688a6f845 Mon Sep 17 00:00:00 2001 From: Don Wilson Date: Tue, 2 Nov 2010 08:38:40 -0600 Subject: Added :negative_format option to number_to_currency function [#5894 state:resolved] Signed-off-by: Andrew White --- .../lib/action_view/helpers/number_helper.rb | 23 +++++++++++++++------- .../test/template/number_helper_i18n_test.rb | 5 ++++- actionpack/test/template/number_helper_test.rb | 4 ++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 1488e72c6e..42e2100099 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -15,7 +15,7 @@ module ActionView # unchanged if can't be converted into a valid number. module NumberHelper - DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :unit => "$", :separator => ".", :delimiter => ",", + DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :negative_format => "-%u%n", :unit => "$", :separator => ".", :delimiter => ",", :precision => 2, :significant => false, :strip_insignificant_zeros => false } # Raised when argument +number+ param given to the helpers is invalid and @@ -81,12 +81,13 @@ module ActionView # in the +options+ hash. # # ==== Options - # * :locale - Sets the locale to be used for formatting (defaults to current locale). - # * :precision - Sets the level of precision (defaults to 2). - # * :unit - Sets the denomination of the currency (defaults to "$"). - # * :separator - Sets the separator between the units (defaults to "."). - # * :delimiter - Sets the thousands delimiter (defaults to ","). - # * :format - Sets the format of the output string (defaults to "%u%n"). The field types are: + # * :locale - Sets the locale to be used for formatting (defaults to current locale). + # * :precision - Sets the level of precision (defaults to 2). + # * :unit - Sets the denomination of the currency (defaults to "$"). + # * :separator - Sets the separator between the units (defaults to "."). + # * :delimiter - Sets the thousands delimiter (defaults to ","). + # * :format - Sets the format of the output string (defaults to "%u%n"). + # * :negative_format - Sets the format of the output string (defaults to "-" + :format). The field types are: # # %u The currency unit # %n The number @@ -97,6 +98,8 @@ module ActionView # number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506 # number_to_currency(1234567890.506, :locale => :fr) # => 1 234 567 890,506 € # + # number_to_currency(1234567890.50, :negative_format => "(%u%n)") + # # => ($1,234,567,890.51) # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "") # # => £1234567890,50 # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "", :format => "%n %u") @@ -110,11 +113,17 @@ module ActionView currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {}) defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency) + defaults[:negative_format] = "-" + options[:format] if options[:format] options = defaults.merge!(options) unit = options.delete(:unit) format = options.delete(:format) + if number.to_f < 0 + format = options.delete(:negative_format) + number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '') + end + begin value = number_with_precision(number, options.merge(:raise => true)) format.gsub(/%n/, value).gsub(/%u/, unit).html_safe diff --git a/actionpack/test/template/number_helper_i18n_test.rb b/actionpack/test/template/number_helper_i18n_test.rb index c82ead663f..5df09b4d3b 100644 --- a/actionpack/test/template/number_helper_i18n_test.rb +++ b/actionpack/test/template/number_helper_i18n_test.rb @@ -7,7 +7,7 @@ class NumberHelperTest < ActionView::TestCase I18n.backend.store_translations 'ts', :number => { :format => { :precision => 3, :delimiter => ',', :separator => '.', :significant => false, :strip_insignificant_zeros => false }, - :currency => { :format => { :unit => '&$', :format => '%u - %n', :precision => 2 } }, + :currency => { :format => { :unit => '&$', :format => '%u - %n', :negative_format => '(%u - %n)', :precision => 2 } }, :human => { :format => { :precision => 2, @@ -43,11 +43,14 @@ class NumberHelperTest < ActionView::TestCase def test_number_to_i18n_currency assert_equal("&$ - 10.00", number_to_currency(10, :locale => 'ts')) + assert_equal("(&$ - 10.00)", number_to_currency(-10, :locale => 'ts')) + assert_equal("-10.00 - &$", number_to_currency(-10, :locale => 'ts', :format => "%n - %u")) end def test_number_to_currency_with_clean_i18n_settings clean_i18n do assert_equal("$10.00", number_to_currency(10)) + assert_equal("-$10.00", number_to_currency(-10)) end end diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb index dcdf28ddd5..ab127521ad 100644 --- a/actionpack/test/template/number_helper_test.rb +++ b/actionpack/test/template/number_helper_test.rb @@ -45,11 +45,15 @@ class NumberHelperTest < ActionView::TestCase def test_number_to_currency assert_equal("$1,234,567,890.50", number_to_currency(1234567890.50)) assert_equal("$1,234,567,890.51", number_to_currency(1234567890.506)) + assert_equal("-$1,234,567,890.50", number_to_currency(-1234567890.50)) + assert_equal("-$ 1,234,567,890.50", number_to_currency(-1234567890.50, {:format => "%u %n"})) + assert_equal("($1,234,567,890.50)", number_to_currency(-1234567890.50, {:negative_format => "(%u%n)"})) assert_equal("$1,234,567,892", number_to_currency(1234567891.50, {:precision => 0})) assert_equal("$1,234,567,890.5", number_to_currency(1234567890.50, {:precision => 1})) assert_equal("£1234567890,50", number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""})) assert_equal("$1,234,567,890.50", number_to_currency("1234567890.50")) assert_equal("1,234,567,890.50 Kč", number_to_currency("1234567890.50", {:unit => "Kč", :format => "%n %u"})) + assert_equal("1,234,567,890.50 - Kč", number_to_currency("-1234567890.50", {:unit => "Kč", :format => "%n %u", :negative_format => "%n - %u"})) end def test_number_to_percentage -- cgit v1.2.3 From 208fb2920d6c6c6be97a7086cea24f4c8220010c Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 3 Nov 2010 06:20:26 +0100 Subject: made a pass to the docs of :negative_format --- actionpack/lib/action_view/helpers/number_helper.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 42e2100099..a9400c347f 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -86,11 +86,13 @@ module ActionView # * :unit - Sets the denomination of the currency (defaults to "$"). # * :separator - Sets the separator between the units (defaults to "."). # * :delimiter - Sets the thousands delimiter (defaults to ","). - # * :format - Sets the format of the output string (defaults to "%u%n"). - # * :negative_format - Sets the format of the output string (defaults to "-" + :format). The field types are: - # - # %u The currency unit - # %n The number + # * :format - Sets the format for non-negative numbers (defaults to "%u%n"). + # Fields are %u for the currency, and %n + # for the number. + # * :negative_format - Sets the format for negative numbers (defaults to prepending + # an hyphen to the formatted number given by :format). + # Accepts the same fields than :format, except + # %n is here the absolute value of the number. # # ==== Examples # number_to_currency(1234567890.50) # => $1,234,567,890.50 -- cgit v1.2.3 From ea0faa2055fbbe6ac9ebe960ddf4bea8adda287a Mon Sep 17 00:00:00 2001 From: Jeremy Holland Date: Sun, 31 Oct 2010 22:16:55 -0500 Subject: Allowing to_xml :camelize option to be set to :lower to enable lower-camelcase tags [#5903 state:resolved] --- activemodel/test/cases/serializeration/xml_serialization_test.rb | 7 +++++++ activesupport/lib/active_support/xml_mini.rb | 8 +++++++- activesupport/test/core_ext/hash_ext_test.rb | 9 ++++++++- activesupport/test/test_xml_mini.rb | 4 ++-- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/activemodel/test/cases/serializeration/xml_serialization_test.rb b/activemodel/test/cases/serializeration/xml_serialization_test.rb index ff786658b7..cc19d322b3 100644 --- a/activemodel/test/cases/serializeration/xml_serialization_test.rb +++ b/activemodel/test/cases/serializeration/xml_serialization_test.rb @@ -70,6 +70,13 @@ class XmlSerializationTest < ActiveModel::TestCase assert_match %r{ 'xml_contact', :camelize => :lower + assert_match %r{^}, @xml + assert_match %r{$}, @xml + assert_match %r{ true assert_match %r{25}, @xml diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index b6a8cf3caf..a1728ab955 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -128,7 +128,13 @@ module ActiveSupport def rename_key(key, options = {}) camelize = options.has_key?(:camelize) && options[:camelize] dasherize = !options.has_key?(:dasherize) || options[:dasherize] - key = key.camelize if camelize + if camelize + if options[:camelize] == :lower + key = key.camelize(:lower) + else + key = key.camelize + end + end key = _dasherize(key) if dasherize key end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 545fed2684..cdf27ba35a 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -486,7 +486,7 @@ class HashExtToParamTests < Test::Unit::TestCase def test_to_param_hash_escapes_its_keys_and_values assert_equal 'param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped', { 'param 1' => 'A string with / characters & that should be ? escaped' }.to_param end - + def test_to_param_orders_by_key_in_ascending_order assert_equal 'a=2&b=1&c=0', ActiveSupport::OrderedHash[*%w(b 1 c 0 a 2)].to_param end @@ -525,6 +525,13 @@ class HashToXmlTest < Test::Unit::TestCase assert xml.include?(%(David)) end + def test_one_level_camelize_lower + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => :lower)) + assert_equal "", xml.first(8) + assert xml.include?(%(Paulina)) + assert xml.include?(%(David)) + end + def test_one_level_with_types xml = { :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes }.to_xml(@xml_options) assert_equal "", xml.first(8) diff --git a/activesupport/test/test_xml_mini.rb b/activesupport/test/test_xml_mini.rb index 585eb15c6e..b14a3e1546 100644 --- a/activesupport/test/test_xml_mini.rb +++ b/activesupport/test/test_xml_mini.rb @@ -18,8 +18,8 @@ class XmlMiniTest < Test::Unit::TestCase assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) end - def test_rename_key_camelizes_with_camelize_true - assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) + def test_rename_key_lower_camelizes_with_camelize_lower + assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :lower) end def test_rename_key_does_not_dasherize_leading_underscores -- cgit v1.2.3 From 63625388154043dd6cde755f62c095dad87ad173 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 3 Nov 2010 11:02:42 -0700 Subject: add more tests surrounding camlize in xmlmini, refactor rename_key() --- activesupport/lib/active_support/xml_mini.rb | 8 ++------ activesupport/test/test_xml_mini.rb | 12 ++++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index a1728ab955..cddfcddb57 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -126,14 +126,10 @@ module ActiveSupport end def rename_key(key, options = {}) - camelize = options.has_key?(:camelize) && options[:camelize] + camelize = options[:camelize] dasherize = !options.has_key?(:dasherize) || options[:dasherize] if camelize - if options[:camelize] == :lower - key = key.camelize(:lower) - else - key = key.camelize - end + key = true == camelize ? key.camelize : key.camelize(camelize) end key = _dasherize(key) if dasherize key diff --git a/activesupport/test/test_xml_mini.rb b/activesupport/test/test_xml_mini.rb index b14a3e1546..309fa234bf 100644 --- a/activesupport/test/test_xml_mini.rb +++ b/activesupport/test/test_xml_mini.rb @@ -14,6 +14,14 @@ class XmlMiniTest < Test::Unit::TestCase assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => false) end + def test_rename_key_camelizes_with_camelize_false + assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :camelize => false) + end + + def test_rename_key_camelizes_with_camelize_nil + assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :camelize => nil) + end + def test_rename_key_camelizes_with_camelize_true assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) end @@ -22,6 +30,10 @@ class XmlMiniTest < Test::Unit::TestCase assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :lower) end + def test_rename_key_lower_camelizes_with_camelize_upper + assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :upper) + end + def test_rename_key_does_not_dasherize_leading_underscores assert_equal "_id", ActiveSupport::XmlMini.rename_key("_id") end -- cgit v1.2.3 From d7ec94f66580abceffd313b943636ef113ffa662 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 3 Nov 2010 17:20:02 -0200 Subject: Just initialize options with an empty hash --- actionpack/lib/action_view/helpers/form_helper.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index d6e175c7e8..80a872068d 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -294,10 +294,9 @@ module ActionView # # If you don't need to attach a form to a model instance, then check out # FormTagHelper#form_tag. - def form_for(record, options = nil, &proc) + def form_for(record, options = {}, &proc) raise ArgumentError, "Missing block" unless block_given? - options ||= {} options[:html] ||= {} case record -- cgit v1.2.3 From d0d30e767d7e9a61ec1d8b8d44894f0ab508b990 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 3 Nov 2010 20:12:08 +0100 Subject: Fix scaffold generator to be aware of namespace in isolated engine --- .../erb/scaffold/templates/_form.html.erb | 2 + .../erb/scaffold/templates/edit.html.erb | 2 + .../erb/scaffold/templates/index.html.erb | 2 + .../generators/erb/scaffold/templates/new.html.erb | 2 + .../erb/scaffold/templates/show.html.erb | 2 + railties/lib/rails/generators/named_base.rb | 8 +- .../rails/resource/resource_generator.rb | 4 +- .../scaffold_controller/templates/controller.rb | 2 + railties/lib/rails/generators/resource_helpers.rb | 4 +- .../scaffold/templates/functional_test.rb | 2 + .../test/generators/namespaced_generators_test.rb | 153 +++++++++++++++++++++ 11 files changed, 178 insertions(+), 5 deletions(-) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb index d12b2ff0e5..c8ee939ad7 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb @@ -1,3 +1,4 @@ +<% without_namespacing do -%> <%%= form_for(@<%= singular_table_name %>) do |f| %> <%% if @<%= singular_table_name %>.errors.any? %>
@@ -21,3 +22,4 @@ <%%= f.submit %>
<%% end %> +<% end -%> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb index e58b9fbd08..d1bfcbc429 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb @@ -1,6 +1,8 @@ +<% without_namespacing do -%>

Editing <%= singular_table_name %>

<%%= render 'form' %> <%%= link_to 'Show', @<%= singular_table_name %> %> | <%%= link_to 'Back', <%= index_helper %>_path %> +<% end -%> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb index 4c46db4d67..435d126ee4 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -1,3 +1,4 @@ +<% without_namespacing do -%>

Listing <%= plural_table_name %>

@@ -25,3 +26,4 @@
<%%= link_to 'New <%= human_name %>', new_<%= singular_table_name %>_path %> +<% end -%> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb index 02ae4d015e..fe4d0971c4 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb @@ -1,5 +1,7 @@ +<% without_namespacing do -%>

New <%= singular_table_name %>

<%%= render 'form' %> <%%= link_to 'Back', <%= index_helper %>_path %> +<% end -%> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index c0e5ccff1e..bc3a87b99f 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb @@ -1,3 +1,4 @@ +<% without_namespacing do -%>

<%%= notice %>

<% for attribute in attributes -%> @@ -10,3 +11,4 @@ <%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> | <%%= link_to 'Back', <%= index_helper %>_path %> +<% end -%> diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 9131a19043..badf981d05 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -30,9 +30,15 @@ module Rails end end + def without_namespacing(&block) + inside_namespace do + concat(capture(&block)) + end + end + def indent(content, multiplier = 2) spaces = " " * multiplier - content.each_line.map {|line| "#{spaces}#{line}" }.join("\n") + content = content.each_line.map {|line| "#{spaces}#{line}" }.join end def wrap_with_namespace(content) diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb index 8a943013d3..c7345f3cfb 100644 --- a/railties/lib/rails/generators/rails/resource/resource_generator.rb +++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb @@ -16,9 +16,9 @@ module Rails def add_resource_route return if options[:actions].present? - route_config = class_path.collect{|namespace| "namespace :#{namespace} do " }.join(" ") + route_config = regular_class_path.collect{|namespace| "namespace :#{namespace} do " }.join(" ") route_config << "resources :#{file_name.pluralize}" - route_config << " end" * class_path.size + route_config << " end" * regular_class_path.size route route_config end end diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index b21340f755..b5317a055b 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -1,3 +1,4 @@ +<% module_namespacing do -%> class <%= controller_class_name %>Controller < ApplicationController # GET <%= route_url %> # GET <%= route_url %>.xml @@ -81,3 +82,4 @@ class <%= controller_class_name %>Controller < ApplicationController end end end +<% end -%> diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 829f4b200a..c9e70468a1 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -34,7 +34,7 @@ module Rails attr_reader :controller_name def controller_class_path - @class_path + class_path end def controller_file_name @@ -46,7 +46,7 @@ module Rails end def controller_class_name - @controller_class_name ||= (controller_class_path + [controller_file_name]).map!{ |m| m.camelize }.join('::') + (controller_class_path + [controller_file_name]).map!{ |m| m.camelize }.join('::') end def controller_i18n_scope diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index f23e495450..964d59d84c 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -1,5 +1,6 @@ require 'test_helper' +<% module_namespacing do -%> class <%= controller_class_name %>ControllerTest < ActionController::TestCase setup do @<%= singular_table_name %> = <%= table_name %>(:one) @@ -47,3 +48,4 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase assert_redirected_to <%= index_helper %>_path end end +<% end -%> diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index d1190fd17d..d61a02d32f 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -3,6 +3,7 @@ require 'rails/generators/rails/controller/controller_generator' require 'rails/generators/rails/model/model_generator' require 'rails/generators/rails/observer/observer_generator' require 'rails/generators/mailer/mailer_generator' +require 'rails/generators/rails/scaffold/scaffold_generator' class NamespacedGeneratorTestCase < Rails::Generators::TestCase def setup @@ -202,3 +203,155 @@ class NamespacedMailerGeneratorTest < NamespacedGeneratorTestCase assert_file "app/views/test_app/notifier" end end + +class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase + include GeneratorsTestHelper + arguments %w(product_line title:string price:integer) + tests Rails::Generators::ScaffoldGenerator + + setup :copy_routes + + def test_scaffold_on_invoke + run_generator + + # Model + assert_file "app/models/test_app/product_line.rb", /module TestApp\n class ProductLine < ActiveRecord::Base/ + assert_file "test/unit/test_app/product_line_test.rb", /module TestApp\n class ProductLineTest < ActiveSupport::TestCase/ + assert_file "test/fixtures/test_app/product_lines.yml" + assert_migration "db/migrate/create_test_app_product_lines.rb" + + # Route + assert_file "config/routes.rb" do |route| + assert_match(/resources :product_lines$/, route) + end + + # Controller + assert_file "app/controllers/test_app/product_lines_controller.rb" do |content| + assert_match(/module TestApp\n class ProductLinesController < ApplicationController/, content) + end + + assert_file "test/functional/test_app/product_lines_controller_test.rb", + /module TestApp\n class ProductLinesControllerTest < ActionController::TestCase/ + + # Views + %w( + index + edit + new + show + _form + ).each { |view| assert_file "app/views/test_app/product_lines/#{view}.html.erb" } + assert_no_file "app/views/layouts/test_app/product_lines.html.erb" + + # Helpers + assert_file "app/helpers/test_app/product_lines_helper.rb" + assert_file "test/unit/helpers/test_app/product_lines_helper_test.rb" + + # Stylesheets + assert_file "public/stylesheets/scaffold.css" + end + + def test_scaffold_on_revoke + run_generator + run_generator ["product_line"], :behavior => :revoke + + # Model + assert_no_file "app/models/test_app/product_line.rb" + assert_no_file "test/unit/test_app/product_line_test.rb" + assert_no_file "test/fixtures/test_app/product_lines.yml" + assert_no_migration "db/migrate/create_test_app_product_lines.rb" + + # Route + assert_file "config/routes.rb" do |route| + assert_no_match(/resources :product_lines$/, route) + end + + # Controller + assert_no_file "app/controllers/test_app/product_lines_controller.rb" + assert_no_file "test/functional/test_app/product_lines_controller_test.rb" + + # Views + assert_no_file "app/views/test_app/product_lines" + assert_no_file "app/views/test_app/layouts/product_lines.html.erb" + + # Helpers + assert_no_file "app/helpers/test_app/product_lines_helper.rb" + assert_no_file "test/unit/helpers/test_app/product_lines_helper_test.rb" + + # Stylesheets (should not be removed) + assert_file "public/stylesheets/scaffold.css" + end + + def test_scaffold_with_namespace_on_invoke + run_generator [ "admin/role", "name:string", "description:string" ] + + # Model + assert_file "app/models/test_app/admin.rb", /module TestApp\n module Admin/ + assert_file "app/models/test_app/admin/role.rb", /module TestApp\n class Admin::Role < ActiveRecord::Base/ + assert_file "test/unit/test_app/admin/role_test.rb", /module TestApp\n class Admin::RoleTest < ActiveSupport::TestCase/ + assert_file "test/fixtures/test_app/admin/roles.yml" + assert_migration "db/migrate/create_test_app_admin_roles.rb" + + # Route + assert_file "config/routes.rb" do |route| + assert_match(/namespace :admin do resources :roles end$/, route) + end + + # Controller + assert_file "app/controllers/test_app/admin/roles_controller.rb" do |content| + assert_match(/module TestApp\n class Admin::RolesController < ApplicationController/, content) + end + + assert_file "test/functional/test_app/admin/roles_controller_test.rb", + /module TestApp\n class Admin::RolesControllerTest < ActionController::TestCase/ + + # Views + %w( + index + edit + new + show + _form + ).each { |view| assert_file "app/views/test_app/admin/roles/#{view}.html.erb" } + assert_no_file "app/views/layouts/admin/roles.html.erb" + + # Helpers + assert_file "app/helpers/test_app/admin/roles_helper.rb" + assert_file "test/unit/helpers/test_app/admin/roles_helper_test.rb" + + # Stylesheets + assert_file "public/stylesheets/scaffold.css" + end + + def test_scaffold_with_namespace_on_revoke + run_generator [ "admin/role", "name:string", "description:string" ] + run_generator [ "admin/role" ], :behavior => :revoke + + # Model + assert_file "app/models/test_app/admin.rb" # ( should not be remove ) + assert_no_file "app/models/test_app/admin/role.rb" + assert_no_file "test/unit/test_app/admin/role_test.rb" + assert_no_file "test/fixtures/test_app/admin/roles.yml" + assert_no_migration "db/migrate/create_test_app_admin_roles.rb" + + # Route + assert_file "config/routes.rb" do |route| + assert_no_match(/namespace :admin do resources :roles end$/, route) + end + + # Controller + assert_no_file "app/controllers/test_app/admin/roles_controller.rb" + assert_no_file "test/functional/test_app/admin/roles_controller_test.rb" + + # Views + assert_no_file "app/views/test_app/admin/roles" + assert_no_file "app/views/layouts/test_app/admin/roles.html.erb" + + # Helpers + assert_no_file "app/helpers/test_app/admin/roles_helper.rb" + assert_no_file "test/unit/helpers/test_app/admin/roles_helper_test.rb" + + # Stylesheets (should not be removed) + assert_file "public/stylesheets/scaffold.css" + end +end -- cgit v1.2.3 From 5c6978608d0b05613df6f9ebcb930d0850f44121 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 3 Nov 2010 10:37:23 -0700 Subject: use bind params in select with query monkeypatch --- activerecord/test/connections/native_oracle/connection.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/connections/native_oracle/connection.rb b/activerecord/test/connections/native_oracle/connection.rb index c942036128..b77cc940b6 100644 --- a/activerecord/test/connections/native_oracle/connection.rb +++ b/activerecord/test/connections/native_oracle/connection.rb @@ -37,10 +37,10 @@ Course.establish_connection 'arunit2' ActiveRecord::Base.connection.class.class_eval do IGNORED_SELECT_SQL = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from ((all|user)_tab_columns|(all|user)_triggers|(all|user)_constraints)/im] - def select_with_query_record(sql, name = nil) + def select_with_query_record(sql, name = nil, binds = []) $queries_executed ||= [] $queries_executed << sql unless IGNORED_SELECT_SQL.any? { |r| sql =~ r } - select_without_query_record(sql, name) + select_without_query_record(sql, name, binds) end alias_method_chain :select, :query_record -- cgit v1.2.3 From 6367e9586708e630906746a867a0f3590d3fbf62 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 3 Nov 2010 14:48:40 -0700 Subject: select goes through exec(), so no method chaining for query counts --- activerecord/test/connections/native_oracle/connection.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/activerecord/test/connections/native_oracle/connection.rb b/activerecord/test/connections/native_oracle/connection.rb index b77cc940b6..99f921879c 100644 --- a/activerecord/test/connections/native_oracle/connection.rb +++ b/activerecord/test/connections/native_oracle/connection.rb @@ -33,15 +33,3 @@ ActiveRecord::Base.configurations = { ActiveRecord::Base.establish_connection 'arunit' Course.establish_connection 'arunit2' -# for assert_queries test helper -ActiveRecord::Base.connection.class.class_eval do - IGNORED_SELECT_SQL = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from ((all|user)_tab_columns|(all|user)_triggers|(all|user)_constraints)/im] - - def select_with_query_record(sql, name = nil, binds = []) - $queries_executed ||= [] - $queries_executed << sql unless IGNORED_SELECT_SQL.any? { |r| sql =~ r } - select_without_query_record(sql, name, binds) - end - - alias_method_chain :select, :query_record -end -- cgit v1.2.3 From fa4686243cb4850297c865f3e1de56e790ebc0ec Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 3 Nov 2010 14:57:52 -0700 Subject: ignoring certain SQL when using Oracle --- activerecord/test/cases/helper.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index f6ef155d66..8b0f3a739d 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -48,6 +48,10 @@ end ActiveRecord::Base.connection.class.class_eval do IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /SHOW FIELDS/] + # FIXME: this needs to be refactored so specific database can add their own + # ignored SQL. This ignored SQL is for Oracle. + IGNORED_SQL.concat [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from ((all|user)_tab_columns|(all|user)_triggers|(all|user)_constraints)/im] + def execute_with_query_record(sql, name = nil, &block) $queries_executed ||= [] $queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r } -- cgit v1.2.3 From 3bb1ad32bf5a24524870345b099e8361ce62e9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 4 Nov 2010 10:39:15 -0200 Subject: Update to latest thor. --- railties/railties.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/railties.gemspec b/railties/railties.gemspec index d26c1bcdbc..c3793d3ac3 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -20,7 +20,7 @@ Gem::Specification.new do |s| s.has_rdoc = false s.add_dependency('rake', '>= 0.8.7') - s.add_dependency('thor', '~> 0.14.3') + s.add_dependency('thor', '~> 0.14.4') s.add_dependency('activesupport', version) s.add_dependency('actionpack', version) end -- cgit v1.2.3 From 1fd46240a61efa72c2e1259fbeafae5cfd8a6df9 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 4 Nov 2010 20:04:57 +0100 Subject: New version of thor was released no need to use the one from git --- Gemfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Gemfile b/Gemfile index ac9c63790c..66a446a177 100644 --- a/Gemfile +++ b/Gemfile @@ -6,8 +6,6 @@ else gem "arel", :git => "git://github.com/rails/arel.git" end -gem "thor", :git => "git://github.com/wycats/thor.git" - gem "rack", :git => "git://github.com/rack/rack.git" gem "rails", :path => File.dirname(__FILE__) -- cgit v1.2.3 From 710dcf826a073720b817389fe1b7013fb87be659 Mon Sep 17 00:00:00 2001 From: sblackstone Date: Wed, 3 Nov 2010 14:12:28 -0400 Subject: Association Proxy should not undefine the default respond_to_missing --- activerecord/lib/active_record/associations/association_proxy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 0c12c3737d..ac2aa46edf 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -53,7 +53,7 @@ module ActiveRecord alias_method :proxy_respond_to?, :respond_to? alias_method :proxy_extend, :extend delegate :to_param, :to => :proxy_target - instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|proxy_/ } + instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to_missing|proxy_/ } def initialize(owner, reflection) @owner, @reflection = owner, reflection -- cgit v1.2.3 From 9a08517c8dad9824bc24c1c9874343d3d70b5360 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 10:08:38 -0700 Subject: converted exec to exec_query for sqlite --- .../abstract/database_statements.rb | 2 +- .../connection_adapters/sqlite_adapter.rb | 22 ++++++++++---------- .../cases/adapters/sqlite3/sqlite3_adapter_test.rb | 24 +++++++++++----------- activerecord/test/cases/helper.rb | 6 +++--- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 6178130c00..ee9a0af35c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -50,7 +50,7 @@ module ActiveRecord # Executes +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. - def exec(sql, name = 'SQL', binds = []) + def exec_query(sql, name = 'SQL', binds = []) end # Returns the last auto-generated ID from the affected table. diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index fc4d84a4f2..d76fc4103e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -143,7 +143,7 @@ module ActiveRecord # DATABASE STATEMENTS ====================================== - def exec(sql, name = nil, binds = []) + def exec_query(sql, name = nil, binds = []) log(sql, name) do # Don't cache statements without bind values @@ -186,7 +186,7 @@ module ActiveRecord alias :create :insert_sql def select_rows(sql, name = nil) - exec(sql, name).rows + exec_query(sql, name).rows end def begin_db_transaction #:nodoc: @@ -210,7 +210,7 @@ module ActiveRecord WHERE type = 'table' AND NOT name = 'sqlite_sequence' SQL - exec(sql, name).map do |row| + exec_query(sql, name).map do |row| row['name'] end end @@ -222,12 +222,12 @@ module ActiveRecord end def indexes(table_name, name = nil) #:nodoc: - exec("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row| + exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row| IndexDefinition.new( table_name, row['name'], row['unique'] != 0, - exec("PRAGMA index_info('#{row['name']}')").map { |col| + exec_query("PRAGMA index_info('#{row['name']}')").map { |col| col['name'] }) end @@ -241,11 +241,11 @@ module ActiveRecord end def remove_index!(table_name, index_name) #:nodoc: - exec "DROP INDEX #{quote_column_name(index_name)}" + exec_query "DROP INDEX #{quote_column_name(index_name)}" end def rename_table(name, new_name) - exec "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}" + exec_query "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}" end # See: http://www.sqlite.org/lang_altertable.html @@ -282,7 +282,7 @@ module ActiveRecord def change_column_null(table_name, column_name, null, default = nil) unless null || default.nil? - exec("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") + exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") end alter_table(table_name) do |definition| definition[column_name].null = null @@ -314,7 +314,7 @@ module ActiveRecord protected def select(sql, name = nil, binds = []) #:nodoc: - result = exec(sql, name, binds) + result = exec_query(sql, name, binds) columns = result.columns.map { |column| column.sub(/^"?\w+"?\./, '') } @@ -399,11 +399,11 @@ module ActiveRecord quoted_columns = columns.map { |col| quote_column_name(col) } * ',' quoted_to = quote_table_name(to) - exec("SELECT * FROM #{quote_table_name(from)}").each do |row| + exec_query("SELECT * FROM #{quote_table_name(from)}").each do |row| sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES (" sql << columns.map {|col| quote row[column_mappings[col]]} * ', ' sql << ')' - exec sql + exec_query sql end end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 973c51f3d7..234696adeb 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -58,24 +58,24 @@ module ActiveRecord end def test_exec_no_binds - @conn.exec('create table ex(id int, data string)') - result = @conn.exec('SELECT id, data FROM ex') + @conn.exec_query('create table ex(id int, data string)') + result = @conn.exec_query('SELECT id, data FROM ex') assert_equal 0, result.rows.length assert_equal 2, result.columns.length assert_equal %w{ id data }, result.columns - @conn.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @conn.exec('SELECT id, data FROM ex') + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @conn.exec_query('SELECT id, data FROM ex') assert_equal 1, result.rows.length assert_equal 2, result.columns.length assert_equal [[1, 'foo']], result.rows end - def test_exec_with_binds - @conn.exec('create table ex(id int, data string)') - @conn.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @conn.exec( + def test_exec_query_with_binds + @conn.exec_query('create table ex(id int, data string)') + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @conn.exec_query( 'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]]) assert_equal 1, result.rows.length @@ -84,12 +84,12 @@ module ActiveRecord assert_equal [[1, 'foo']], result.rows end - def test_exec_typecasts_bind_vals - @conn.exec('create table ex(id int, data string)') - @conn.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') + def test_exec_query_typecasts_bind_vals + @conn.exec_query('create table ex(id int, data string)') + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') column = @conn.columns('ex').find { |col| col.name == 'id' } - result = @conn.exec( + result = @conn.exec_query( 'SELECT id, data FROM ex WHERE id = ?', nil, [[column, '1-fuu']]) assert_equal 1, result.rows.length diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 8b0f3a739d..52f26b71f5 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -60,13 +60,13 @@ ActiveRecord::Base.connection.class.class_eval do alias_method_chain :execute, :query_record - def exec_with_query_record(sql, name = nil, binds = [], &block) + def exec_query_with_query_record(sql, name = nil, binds = [], &block) $queries_executed ||= [] $queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r } - exec_without_query_record(sql, name, binds, &block) + exec_query_without_query_record(sql, name, binds, &block) end - alias_method_chain :exec, :query_record + alias_method_chain :exec_query, :query_record end ActiveRecord::Base.connection.class.class_eval { -- cgit v1.2.3 From 0f45f2366945a19e1413d15608b917e1b7987fa5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 10:15:33 -0700 Subject: renaming exec in the PG adapter --- .../connection_adapters/postgresql_adapter.rb | 6 +++--- .../adapters/postgresql/postgresql_adapter_test.rb | 18 +++++++++--------- .../adapters/postgresql/schema_authorization_test.rb | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 58c0f85dc2..426360b470 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -398,7 +398,7 @@ module ActiveRecord # Set the authorized user for this session def session_auth=(user) clear_cache! - exec "SET SESSION AUTHORIZATION #{user}" + exec_query "SET SESSION AUTHORIZATION #{user}" end # REFERENTIAL INTEGRITY ==================================== @@ -532,7 +532,7 @@ module ActiveRecord Arel.sql("$#{current_values.length + 1}") end - def exec(sql, name = 'SQL', binds = []) + def exec_query(sql, name = 'SQL', binds = []) return exec_no_cache(sql, name) if binds.empty? log(sql, name) do @@ -1040,7 +1040,7 @@ module ActiveRecord # Executes a SELECT query and returns the results, performing any data type # conversions that are required to be performed here instead of in PostgreSQLColumn. def select(sql, name = nil, binds = []) - exec(sql, name, binds).to_a + exec_query(sql, name, binds).to_a end def select_raw(sql, name = nil) diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index b0fd2273df..b0a4a4e39d 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -5,8 +5,8 @@ module ActiveRecord class PostgreSQLAdapterTest < ActiveRecord::TestCase def setup @connection = ActiveRecord::Base.connection - @connection.exec('drop table if exists ex') - @connection.exec('create table ex(id serial primary key, data character varying(255))') + @connection.exec_query('drop table if exists ex') + @connection.exec_query('create table ex(id serial primary key, data character varying(255))') end def test_table_alias_length @@ -16,14 +16,14 @@ module ActiveRecord end def test_exec_no_binds - result = @connection.exec('SELECT id, data FROM ex') + result = @connection.exec_query('SELECT id, data FROM ex') assert_equal 0, result.rows.length assert_equal 2, result.columns.length assert_equal %w{ id data }, result.columns string = @connection.quote('foo') - @connection.exec("INSERT INTO ex (id, data) VALUES (1, #{string})") - result = @connection.exec('SELECT id, data FROM ex') + @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") + result = @connection.exec_query('SELECT id, data FROM ex') assert_equal 1, result.rows.length assert_equal 2, result.columns.length @@ -32,8 +32,8 @@ module ActiveRecord def test_exec_with_binds string = @connection.quote('foo') - @connection.exec("INSERT INTO ex (id, data) VALUES (1, #{string})") - result = @connection.exec( + @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") + result = @connection.exec_query( 'SELECT id, data FROM ex WHERE id = $1', nil, [[nil, 1]]) assert_equal 1, result.rows.length @@ -44,10 +44,10 @@ module ActiveRecord def test_exec_typecasts_bind_vals string = @connection.quote('foo') - @connection.exec("INSERT INTO ex (id, data) VALUES (1, #{string})") + @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") column = @connection.columns('ex').find { |col| col.name == 'id' } - result = @connection.exec( + result = @connection.exec_query( 'SELECT id, data FROM ex WHERE id = $1', nil, [[column, '1-fuu']]) assert_equal 1, result.rows.length diff --git a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb index 881631fb19..d5e1838543 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb @@ -55,7 +55,7 @@ class SchemaAuthorizationTest < ActiveRecord::TestCase set_session_auth USERS.each do |u| set_session_auth u - assert_equal u, @connection.exec("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [[nil, 1]]).first['name'] + assert_equal u, @connection.exec_query("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [[nil, 1]]).first['name'] set_session_auth end end @@ -67,7 +67,7 @@ class SchemaAuthorizationTest < ActiveRecord::TestCase USERS.each do |u| @connection.clear_cache! set_session_auth u - assert_equal u, @connection.exec("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [[nil, 1]]).first['name'] + assert_equal u, @connection.exec_query("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [[nil, 1]]).first['name'] set_session_auth end end -- cgit v1.2.3 From d5e45931a0f3d36515d6048fd9cb13f641018571 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 10:21:14 -0700 Subject: renaming exec in the mysql adapter --- .../connection_adapters/mysql_adapter.rb | 4 ++-- .../test/cases/adapters/mysql/connection_test.rb | 26 +++++++++++----------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 7d47d06ae1..ce2352486b 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -326,7 +326,7 @@ module ActiveRecord @statements.clear end - def exec(sql, name = 'SQL', binds = []) + def exec_query(sql, name = 'SQL', binds = []) log(sql, name) do result = nil @@ -708,7 +708,7 @@ module ActiveRecord def select(sql, name = nil, binds = []) @connection.query_with_result = true - rows = exec(sql, name, binds).to_a + rows = exec_query(sql, name, binds).to_a @connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped rows end diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb index 67bd8ec7e0..62ffde558f 100644 --- a/activerecord/test/cases/adapters/mysql/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql/connection_test.rb @@ -49,18 +49,18 @@ class MysqlConnectionTest < ActiveRecord::TestCase end def test_exec_no_binds - @connection.exec('drop table if exists ex') - @connection.exec(<<-eosql) + @connection.exec_query('drop table if exists ex') + @connection.exec_query(<<-eosql) CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `data` varchar(255)) eosql - result = @connection.exec('SELECT id, data FROM ex') + result = @connection.exec_query('SELECT id, data FROM ex') assert_equal 0, result.rows.length assert_equal 2, result.columns.length assert_equal %w{ id data }, result.columns - @connection.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @connection.exec('SELECT id, data FROM ex') + @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @connection.exec_query('SELECT id, data FROM ex') assert_equal 1, result.rows.length assert_equal 2, result.columns.length @@ -68,13 +68,13 @@ class MysqlConnectionTest < ActiveRecord::TestCase end def test_exec_with_binds - @connection.exec('drop table if exists ex') - @connection.exec(<<-eosql) + @connection.exec_query('drop table if exists ex') + @connection.exec_query(<<-eosql) CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `data` varchar(255)) eosql - @connection.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @connection.exec( + @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @connection.exec_query( 'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]]) assert_equal 1, result.rows.length @@ -84,15 +84,15 @@ class MysqlConnectionTest < ActiveRecord::TestCase end def test_exec_typecasts_bind_vals - @connection.exec('drop table if exists ex') - @connection.exec(<<-eosql) + @connection.exec_query('drop table if exists ex') + @connection.exec_query(<<-eosql) CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `data` varchar(255)) eosql - @connection.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') + @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') column = @connection.columns('ex').find { |col| col.name == 'id' } - result = @connection.exec( + result = @connection.exec_query( 'SELECT id, data FROM ex WHERE id = ?', nil, [[column, '1-fuu']]) assert_equal 1, result.rows.length -- cgit v1.2.3 From 3146aa68fd03ea4392b45f1c8771675a9c850471 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 4 Nov 2010 20:48:02 -0200 Subject: Fixes queries using limits and punctuation in order, removes order("col1, col2") usage in favor of order(["col1", "col2"}) [#4597 state:committed] --- .../connection_adapters/postgresql_adapter.rb | 6 +++--- .../lib/active_record/relation/finder_methods.rb | 2 +- .../associations/cascaded_eager_loading_test.rb | 2 +- activerecord/test/cases/associations/eager_test.rb | 4 ++-- activerecord/test/cases/relations_test.rb | 23 +++++++++++++++++++++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 426360b470..942ea9b297 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -932,12 +932,12 @@ module ActiveRecord # requires that the ORDER BY include the distinct column. # # distinct("posts.id", "posts.created_at desc") - def distinct(columns, order_by) #:nodoc: - return "DISTINCT #{columns}" if order_by.blank? + def distinct(columns, orders) #:nodoc: + return "DISTINCT #{columns}" if orders.empty? # Construct a clean list of column names from the ORDER BY clause, removing # any ASC/DESC modifiers - order_columns = order_by.split(',').collect { |s| s.split.first } + order_columns = orders.collect { |s| s.split.first } order_columns.delete_if { |c| c.blank? } order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" } diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index fe1ef2e2e3..ab9f10b380 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -222,7 +222,7 @@ module ActiveRecord end def construct_limited_ids_condition(relation) - orders = relation.order_values.join(", ") + orders = relation.order_values values = @klass.connection.distinct("#{@klass.connection.quote_table_name @klass.table_name}.#{@klass.primary_key}", orders) ids_array = relation.select(values).collect {|row| row[@klass.primary_key]} diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index 271bb92ee8..37c6f354a8 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -137,7 +137,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_multiple_stis_and_order - author = Author.find(:first, :include => { :posts => [ :special_comments , :very_special_comment ] }, :order => 'authors.name, comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4') + author = Author.find(:first, :include => { :posts => [ :special_comments , :very_special_comment ] }, :order => ['authors.name', 'comments.body', 'very_special_comments_posts.body'], :conditions => 'posts.id = 4') assert_equal authors(:david), author assert_no_queries do author.posts.first.special_comments diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 2d8e02e398..b559c9ddad 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -584,8 +584,8 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_limited_eager_with_multiple_order_columns - assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title), posts.id', :limit => 2, :offset => 1) - assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC, posts.id', :limit => 2, :offset => 1) + assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => ['UPPER(posts.title)', 'posts.id'], :limit => 2, :offset => 1) + assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => ['UPPER(posts.title) DESC', 'posts.id'], :limit => 2, :offset => 1) end def test_limited_eager_with_numeric_in_association diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index f4f3dc4d5a..fbc257195c 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require 'models/tag' require 'models/tagging' require 'models/post' require 'models/topic' @@ -17,7 +18,7 @@ require 'models/tyre' class RelationTest < ActiveRecord::TestCase fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments, - :taggings, :cars + :tags, :taggings, :cars def test_bind_values relation = Post.scoped @@ -144,6 +145,26 @@ class RelationTest < ActiveRecord::TestCase assert_equal entrants(:first).name, entrants.first.name end + def test_finding_with_complex_order_and_limit + if current_adapter?(:SQLite3Adapter) + tags = Tag.includes(:taggings).order("MIN(1,2)").limit(1).to_a + else + tags = Tag.includes(:taggings).order("LEAST(1,COS(1)*COS(-1)*COS(RADIANS(taggings.super_tag_id)))").limit(1).to_a + end + + assert_equal 1, tags.length + end + + def test_finding_with_complex_order + if current_adapter?(:SQLite3Adapter) + tags = Tag.includes(:taggings).order("MIN(1,2)").to_a + else + tags = Tag.includes(:taggings).order("LEAST(1,COS(1)*COS(-1)*COS(RADIANS(taggings.super_tag_id)))").to_a + end + + assert_equal 2, tags.length + end + def test_finding_with_order_limit_and_offset entrants = Entrant.order("id ASC").limit(2).offset(1) -- cgit v1.2.3 From 00261a187ef55c284156ef22b31909ffbe51b0f2 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 4 Nov 2010 21:11:33 -0200 Subject: Avoid warning: shadowing outer local variable --- .../lib/active_record/connection_adapters/postgresql_adapter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 942ea9b297..e7fb8524ce 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -714,8 +714,8 @@ module ActiveRecord # Returns the list of all column definitions for a table. def columns(table_name, name = nil) # Limit, precision, and scale are all handled by the superclass. - column_definitions(table_name).collect do |name, type, default, notnull| - PostgreSQLColumn.new(name, default, type, notnull == 'f') + column_definitions(table_name).collect do |column_name, type, default, notnull| + PostgreSQLColumn.new(column_name, default, type, notnull == 'f') end end -- cgit v1.2.3 From 29b54a41d9cd9b5b8902429be4adedf4a296fa9d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 5 Nov 2010 19:11:58 -0200 Subject: Bring back ruby-debug19 for Ruby versions < 1.9.3 --- Gemfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index 66a446a177..3aaf9a6123 100644 --- a/Gemfile +++ b/Gemfile @@ -31,6 +31,11 @@ platforms :mri_18 do gem 'ruby-prof' end +platforms :mri_19 do + # TODO: Remove the conditional when ruby-debug19 supports Ruby >= 1.9.3 + gem "ruby-debug19" if RUBY_VERSION < "1.9.3" +end + platforms :ruby do gem 'json' gem 'yajl-ruby' -- cgit v1.2.3 From 06d518a32398a4dc7564f45aa19575ea7fa702da Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 11:48:40 -0700 Subject: stop recursively calling exists? --- activerecord/lib/active_record/relation/finder_methods.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index ab9f10b380..e9e9c85122 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -171,14 +171,16 @@ module ActiveRecord def exists?(id = nil) id = id.id if ActiveRecord::Base === id + relation = select(primary_key).limit(1) + case id when Array, Hash - where(id).exists? + relation = relation.where(id) else - relation = select(primary_key).limit(1) relation = relation.where(primary_key.eq(id)) if id - relation.first ? true : false end + + relation.first ? true : false end protected -- cgit v1.2.3 From b1667c7c2c1aba4a2adb5f36ad9499c01763655d Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Fri, 5 Nov 2010 10:28:35 +0800 Subject: Correctly handle the case of an API response that returns a hash by treating a single hash argument as the resource instead of as options. --- actionpack/lib/action_controller/metal/mime_responds.rb | 2 +- actionpack/test/controller/mime_responds_test.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index c6d4c6d936..f7dd0dcb69 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -227,7 +227,7 @@ module ActionController #:nodoc: "controller responds to in the class level" if self.class.mimes_for_respond_to.empty? if response = retrieve_response_from_mimes(&block) - options = resources.extract_options! + options = resources.size == 1 ? {} : resources.extract_options! options.merge!(:default_response => response) (options.delete(:responder) || self.class.responder).call(self, resources, options) end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index a898ef76e5..b6ce9f7d34 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -487,6 +487,10 @@ class RespondWithController < ActionController::Base respond_with(resource) end + def using_hash_resource + respond_with({:result => resource}) + end + def using_resource_with_block respond_with(resource) do |format| format.csv { render :text => "CSV" } @@ -587,6 +591,18 @@ class RespondWithControllerTest < ActionController::TestCase end end + def test_using_hash_resource + @request.accept = "application/xml" + get :using_hash_resource + assert_equal "application/xml", @response.content_type + assert_equal "\n\n david\n\n", @response.body + + @request.accept = "application/json" + get :using_hash_resource + assert_equal "application/json", @response.content_type + assert_equal %Q[{"result":["david",13]}], @response.body + end + def test_using_resource_with_block @request.accept = "*/*" get :using_resource_with_block -- cgit v1.2.3 From a79e1de90a6062926a8ec11870702923eb691944 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 16:27:39 -0700 Subject: reduce method calls to the join base object --- activerecord/lib/active_record/associations.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index dc466eafc2..3d754af5b3 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1874,12 +1874,14 @@ module ActiveRecord end def instantiate(rows) - rows.each_with_index do |row, i| - primary_id = join_base.record_id(row) + primary_key = join_base.aliased_primary_key + + rows.each_with_index do |model, i| + primary_id = model[primary_key] unless @base_records_hash[primary_id] - @base_records_in_order << (@base_records_hash[primary_id] = join_base.instantiate(row)) + @base_records_in_order << (@base_records_hash[primary_id] = join_base.instantiate(model)) end - construct(@base_records_hash[primary_id], @associations, join_associations.dup, row) + construct(@base_records_hash[primary_id], @associations, join_associations.dup, model) end remove_duplicate_results!(join_base.active_record, @base_records_in_order, @associations) return @base_records_in_order -- cgit v1.2.3 From d89d70236177a074b8357b6104248c86c30c2502 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 16:30:38 -0700 Subject: index is not used, so removing it --- activerecord/lib/active_record/associations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 3d754af5b3..680810f031 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1876,7 +1876,7 @@ module ActiveRecord def instantiate(rows) primary_key = join_base.aliased_primary_key - rows.each_with_index do |model, i| + rows.each do |model| primary_id = model[primary_key] unless @base_records_hash[primary_id] @base_records_in_order << (@base_records_hash[primary_id] = join_base.instantiate(model)) -- cgit v1.2.3 From c43d909ee28484c5e7d7d84b1228e10212d20737 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 16:56:41 -0700 Subject: simplify instantiate in the join parts object --- activerecord/lib/active_record/associations.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 680810f031..0fc8740dce 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1839,8 +1839,6 @@ module ActiveRecord @join_parts = [JoinBase.new(base, joins)] @associations = {} @reflections = [] - @base_records_hash = {} - @base_records_in_order = [] @table_aliases = Hash.new(0) @table_aliases[base.table_name] = 1 build(associations) @@ -1875,16 +1873,17 @@ module ActiveRecord def instantiate(rows) primary_key = join_base.aliased_primary_key + base_records_hash = {} rows.each do |model| primary_id = model[primary_key] - unless @base_records_hash[primary_id] - @base_records_in_order << (@base_records_hash[primary_id] = join_base.instantiate(model)) - end - construct(@base_records_hash[primary_id], @associations, join_associations.dup, model) + base_records_hash[primary_id] ||= join_base.instantiate(model) + construct(base_records_hash[primary_id], @associations, join_associations.dup, model) end - remove_duplicate_results!(join_base.active_record, @base_records_in_order, @associations) - return @base_records_in_order + + records = base_records_hash.values + remove_duplicate_results!(join_base.active_record, records, @associations) + records end def remove_duplicate_results!(base, records, associations) -- cgit v1.2.3 From 39a80567918af298b39898d78062e7a8fb5da601 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 17:08:56 -0700 Subject: only call to_s on the association variable once --- activerecord/lib/active_record/associations.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 0fc8740dce..8d415cdfdf 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1983,10 +1983,13 @@ module ActiveRecord def construct(parent, associations, join_parts, row) case associations when Symbol, String + associations = associations.to_s + join_part = join_parts.detect { |j| - j.reflection.name.to_s == associations.to_s && + j.reflection.name.to_s == associations && j.parent_table_name == parent.class.table_name } - raise(ConfigurationError, "No such association") if join_part.nil? + + raise(ConfigurationError, "No such association") unless join_part join_parts.delete(join_part) construct_association(parent, join_part, row) -- cgit v1.2.3 From c11102d4f80267e3774985329ea93e7368e8684f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 6 Nov 2010 14:32:41 -0700 Subject: make sure we keep parent records in order --- activerecord/lib/active_record/associations.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 8d415cdfdf..aad0cbb895 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1873,15 +1873,15 @@ module ActiveRecord def instantiate(rows) primary_key = join_base.aliased_primary_key - base_records_hash = {} + parents = {} - rows.each do |model| + records = rows.map { |model| primary_id = model[primary_key] - base_records_hash[primary_id] ||= join_base.instantiate(model) - construct(base_records_hash[primary_id], @associations, join_associations.dup, model) - end + parent = parents[primary_id] ||= join_base.instantiate(model) + construct(parent, @associations, join_associations.dup, model) + parent + }.uniq - records = base_records_hash.values remove_duplicate_results!(join_base.active_record, records, @associations) records end -- cgit v1.2.3 From 2382667955df08599cb5df7bf3ef135817093d74 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 6 Nov 2010 21:00:26 -0200 Subject: Fix problems trying to functional test AC::Metal controllers [#5393 state:committed] --- actionpack/lib/action_controller/metal/testing.rb | 10 +--------- actionpack/lib/action_controller/test_case.rb | 4 ++-- actionpack/test/controller/new_base/bare_metal_test.rb | 7 +++++++ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb index 4b8c452d50..01fd55e1dd 100644 --- a/actionpack/lib/action_controller/metal/testing.rb +++ b/actionpack/lib/action_controller/metal/testing.rb @@ -14,18 +14,10 @@ module ActionController cookies.write(@_response) end @_response.prepare! - set_test_assigns + @assigns = respond_to?(:view_assigns) ? view_assigns : {} ret end - def set_test_assigns - @assigns = {} - (instance_variable_names - self.class.protected_instance_variables).each do |var| - name, value = var[1..-1], instance_variable_get(var) - @assigns[name] = value - end - end - # TODO : Rewrite tests using controller.headers= to use Rack env def headers=(new_headers) @_response ||= ActionDispatch::Response.new diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 0c26071379..cc27233049 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -411,7 +411,7 @@ module ActionController @controller.request = @request @controller.params.merge!(parameters) build_request_uri(action, parameters) - Base.class_eval { include Testing } + @controller.class.class_eval { include Testing } @controller.process_with_new_base_test(@request, @response) @request.session.delete('flash') if @request.session['flash'].blank? @response @@ -448,7 +448,7 @@ module ActionController def build_request_uri(action, parameters) unless @request.env["PATH_INFO"] - options = @controller.__send__(:url_options).merge(parameters) + options = @controller.respond_to?(:url_options) ? @controller.__send__(:url_options).merge(parameters) : parameters options.update( :only_path => true, :action => action, diff --git a/actionpack/test/controller/new_base/bare_metal_test.rb b/actionpack/test/controller/new_base/bare_metal_test.rb index 44922cecff..543c02b2c5 100644 --- a/actionpack/test/controller/new_base/bare_metal_test.rb +++ b/actionpack/test/controller/new_base/bare_metal_test.rb @@ -39,4 +39,11 @@ module BareMetalTest assert_equal 404, status end end + + class BareControllerTest < ActionController::TestCase + test "GET index" do + get :index + assert_equal "Hello world", @response.body + end + end end -- cgit v1.2.3 From 46332e458cc89ca9166099ad7609a4d65a12e48d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 6 Nov 2010 21:07:20 -0200 Subject: Move @assigns from the controller to the test itself --- actionpack/lib/action_controller/metal/testing.rb | 1 - actionpack/lib/action_controller/test_case.rb | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb index 01fd55e1dd..f4efeb33ba 100644 --- a/actionpack/lib/action_controller/metal/testing.rb +++ b/actionpack/lib/action_controller/metal/testing.rb @@ -14,7 +14,6 @@ module ActionController cookies.write(@_response) end @_response.prepare! - @assigns = respond_to?(:view_assigns) ? view_assigns : {} ret end diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index cc27233049..2b2f647d32 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -413,6 +413,7 @@ module ActionController build_request_uri(action, parameters) @controller.class.class_eval { include Testing } @controller.process_with_new_base_test(@request, @response) + @assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {} @request.session.delete('flash') if @request.session['flash'].blank? @response end -- cgit v1.2.3 From 1acc086278c974d7a3cdb0459cd65f73641abe33 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 6 Nov 2010 18:20:02 -0700 Subject: reduce duplication in assiciations #construct() --- activerecord/lib/active_record/associations.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index aad0cbb895..c84673e6a6 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1983,10 +1983,10 @@ module ActiveRecord def construct(parent, associations, join_parts, row) case associations when Symbol, String - associations = associations.to_s + name = associations.to_s join_part = join_parts.detect { |j| - j.reflection.name.to_s == associations && + j.reflection.name.to_s == name && j.parent_table_name == parent.class.table_name } raise(ConfigurationError, "No such association") unless join_part @@ -1999,13 +1999,7 @@ module ActiveRecord end when Hash associations.sort_by { |k,_| k.to_s }.each do |name, assoc| - join_part = join_parts.detect{ |j| - j.reflection.name.to_s == name.to_s && - j.parent_table_name == parent.class.table_name } - raise(ConfigurationError, "No such association") if join_part.nil? - - association = construct_association(parent, join_part, row) - join_parts.delete(join_part) + association = construct(parent, name, join_parts, row) construct(association, assoc, join_parts, row) if association end else -- cgit v1.2.3 From 6709078eb1f61a1f8d54fcd82e9a07e96383ec8a Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sun, 7 Nov 2010 09:54:43 -0200 Subject: use column names as order by complex function parameters, fix for postgresql adapter to correctly remove ASC/DESC Signed-off-by: Santiago Pastorino --- .../connection_adapters/postgresql_adapter.rb | 2 +- activerecord/test/cases/relations_test.rb | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index e7fb8524ce..ccc5085b84 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -937,7 +937,7 @@ module ActiveRecord # Construct a clean list of column names from the ORDER BY clause, removing # any ASC/DESC modifiers - order_columns = orders.collect { |s| s.split.first } + order_columns = orders.collect { |s| s =~ /^(.+)\s+(ASC|DESC)\s*$/i ? $1 : s } order_columns.delete_if { |c| c.blank? } order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" } diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index fbc257195c..0fd2b99937 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -146,22 +146,12 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_complex_order_and_limit - if current_adapter?(:SQLite3Adapter) - tags = Tag.includes(:taggings).order("MIN(1,2)").limit(1).to_a - else - tags = Tag.includes(:taggings).order("LEAST(1,COS(1)*COS(-1)*COS(RADIANS(taggings.super_tag_id)))").limit(1).to_a - end - + tags = Tag.includes(:taggings).order("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").limit(1).to_a assert_equal 1, tags.length end def test_finding_with_complex_order - if current_adapter?(:SQLite3Adapter) - tags = Tag.includes(:taggings).order("MIN(1,2)").to_a - else - tags = Tag.includes(:taggings).order("LEAST(1,COS(1)*COS(-1)*COS(RADIANS(taggings.super_tag_id)))").to_a - end - + tags = Tag.includes(:taggings).order("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").to_a assert_equal 2, tags.length end -- cgit v1.2.3 From 02039e9752bcb214c2ad85859ecf47dcbb892225 Mon Sep 17 00:00:00 2001 From: laserlemon Date: Mon, 11 Oct 2010 21:21:40 -0400 Subject: Ensure that HashWithIndifferentAccess duplication preserves class (for sublclasses) and default value [#5724 state:resolved] Signed-off-by: Santiago Pastorino --- .../lib/active_support/hash_with_indifferent_access.rb | 6 ++++-- activesupport/test/core_ext/hash_ext_test.rb | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index c406dd3c2e..06dd18966e 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -28,7 +28,7 @@ module ActiveSupport end def self.new_from_hash_copying_default(hash) - ActiveSupport::HashWithIndifferentAccess.new(hash).tap do |new_hash| + new(hash).tap do |new_hash| new_hash.default = hash.default end end @@ -97,7 +97,9 @@ module ActiveSupport # Returns an exact copy of the hash. def dup - HashWithIndifferentAccess.new(self) + self.class.new(self).tap do |new_hash| + new_hash.default = default + end end # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index cdf27ba35a..03fbee93a2 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -6,6 +6,9 @@ require 'active_support/ordered_hash' require 'active_support/core_ext/object/conversions' class HashExtTest < Test::Unit::TestCase + class IndifferentHash < HashWithIndifferentAccess + end + def setup @strings = { 'a' => 1, 'b' => 2 } @symbols = { :a => 1, :b => 2 } @@ -267,7 +270,6 @@ class HashExtTest < Test::Unit::TestCase assert_equal 1, h['first'] end - def test_indifferent_subhashes h = {'user' => {'id' => 5}}.with_indifferent_access ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} @@ -276,6 +278,17 @@ class HashExtTest < Test::Unit::TestCase ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} end + def test_indifferent_duplication + # Should preserve default value + h = HashWithIndifferentAccess.new + h.default = '1234' + assert_equal h.default, h.dup.default + + # Should preserve class for subclasses + h = IndifferentHash.new + assert_equal h.class, h.dup.class + end + def test_assert_valid_keys assert_nothing_raised do { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) -- cgit v1.2.3 From 990f52ebd78df77d73a2187751c6e1bb6d4b6033 Mon Sep 17 00:00:00 2001 From: David Trasbo Date: Wed, 13 Oct 2010 20:58:25 +0200 Subject: Make cookies hash in ActionDispatch::TestProcess indifferent access [#5761 state:committed] Signed-off-by: Santiago Pastorino --- actionpack/lib/action_dispatch/testing/test_process.rb | 2 +- actionpack/test/dispatch/cookies_test.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb index c56ebc6438..16f3674164 100644 --- a/actionpack/lib/action_dispatch/testing/test_process.rb +++ b/actionpack/lib/action_dispatch/testing/test_process.rb @@ -22,7 +22,7 @@ module ActionDispatch end def cookies - @request.cookies.merge(@response.cookies) + HashWithIndifferentAccess.new(@request.cookies.merge(@response.cookies)) end def redirect_to_url diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index faeae91f6b..5ec7f12cc1 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -94,6 +94,16 @@ class CookiesTest < ActionController::TestCase cookies.delete(:user_name, :domain => :all) head :ok end + + def symbol_key + cookies[:user_name] = "david" + head :ok + end + + def string_key + cookies['user_name'] = "david" + head :ok + end end tests TestController @@ -291,6 +301,14 @@ class CookiesTest < ActionController::TestCase assert_cookie_header "user_name=; domain=.nextangle.com; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT" end + def test_cookies_hash_is_indifferent_access + [:symbol_key, :string_key].each do |cookie_key| + get cookie_key + assert_equal "david", cookies[:user_name] + assert_equal "david", cookies['user_name'] + end + end + private def assert_cookie_header(expected) header = @response.headers["Set-Cookie"] -- cgit v1.2.3 From 697f4851b8bc4eb539b3e565e8b6349cafed8aaa Mon Sep 17 00:00:00 2001 From: "James A. Rosen" Date: Wed, 20 Oct 2010 08:01:02 -0700 Subject: OrderedHash#select now preserves order [#5843 state:resolved] Signed-off-by: Santiago Pastorino --- activesupport/lib/active_support/ordered_hash.rb | 2 ++ activesupport/test/ordered_hash_test.rb | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index 7f148dc853..8e157d3af4 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -137,6 +137,8 @@ module ActiveSupport alias_method :each_pair, :each + alias_method :select, :find_all + def clear super @keys.clear diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb index 50778b5864..72088854fc 100644 --- a/activesupport/test/ordered_hash_test.rb +++ b/activesupport/test/ordered_hash_test.rb @@ -109,6 +109,14 @@ class OrderedHashTest < Test::Unit::TestCase assert_equal @keys, keys end + def test_find_all + assert_equal @keys, @ordered_hash.find_all { true }.map(&:first) + end + + def test_select + assert_equal @keys, @ordered_hash.select { true }.map(&:first) + end + def test_delete_if copy = @ordered_hash.dup copy.delete('pink') -- cgit v1.2.3 From f04ec6a227b702342d2fb841f94915499bf6101a Mon Sep 17 00:00:00 2001 From: Jan Maurits Faber Date: Sat, 6 Nov 2010 15:13:56 +0100 Subject: Added support for Erubis <%== tag <%== x %> is syntactic sugar for <%= raw(x) %> Signed-off-by: Michael Koziarski [#5918 status:committed] --- actionpack/lib/action_view/template/handlers/erb.rb | 6 +++++- actionpack/test/controller/new_base/render_template_test.rb | 10 ++++++++++ .../lib/active_support/core_ext/string/output_safety.rb | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index b827610456..4c1f3d70ca 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -40,7 +40,11 @@ module ActionView end def add_expr_escaped(src, code) - src << '@output_buffer.append= ' << escaped_expr(code) << ';' + if code =~ BLOCK_EXPR + src << "@output_buffer.safe_append= " << code + else + src << "@output_buffer.safe_concat((" << code << ").to_s);" + end end def add_postamble(src) diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb index d31193a063..9899036fe8 100644 --- a/actionpack/test/controller/new_base/render_template_test.rb +++ b/actionpack/test/controller/new_base/render_template_test.rb @@ -9,6 +9,7 @@ module RenderTemplate "locals.html.erb" => "The secret is <%= secret %>", "xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend", "with_raw.html.erb" => "Hello <%=raw 'this is raw' %>", + "with_implicit_raw.html.erb"=> "Hello <%== 'this is also raw' %>", "test/with_json.html.erb" => "<%= render :template => 'test/with_json.json' %>", "test/with_json.json.erb" => "<%= render :template => 'test/final' %>", "test/final.json.erb" => "{ final: json }", @@ -51,6 +52,10 @@ module RenderTemplate render :template => "with_raw" end + def with_implicit_raw + render :template => "with_implicit_raw" + end + def with_error render :template => "test/with_error" end @@ -99,6 +104,11 @@ module RenderTemplate assert_body "Hello this is raw" assert_status 200 + + get :with_implicit_raw + + assert_body "Hello this is also raw" + assert_status 200 end test "rendering a template with renders another template with other format that renders other template in the same format" do diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 37c206ea3c..435317e4b1 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -73,6 +73,7 @@ end module ActiveSupport #:nodoc: class SafeBuffer < String alias safe_concat concat + alias safe_append= concat def concat(value) if value.html_safe? -- cgit v1.2.3 From 9ecaa803001aa95ff9010c8f5aef71c009577ead Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Mon, 8 Nov 2010 10:10:30 +1300 Subject: Make safe_append= live on AV::OutputBuffer not AS::SafeBuffer Conflicts: actionpack/lib/action_view/template/handlers/erb.rb --- actionpack/lib/action_view/template/handlers/erb.rb | 1 + activesupport/lib/active_support/core_ext/string/output_safety.rb | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index 4c1f3d70ca..0803114f44 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -15,6 +15,7 @@ module ActionView super(value.to_s) end alias :append= :<< + alias :safe_append= :safe_concat end class Template diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 435317e4b1..37c206ea3c 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -73,7 +73,6 @@ end module ActiveSupport #:nodoc: class SafeBuffer < String alias safe_concat concat - alias safe_append= concat def concat(value) if value.html_safe? -- cgit v1.2.3 From 3d6eea0221f0092cb3c3270c2a9bdf31745d1b2d Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Mon, 8 Nov 2010 10:16:40 +1300 Subject: Update the validates_uniqueness_of documentation to tell you to use a unique index. The other options mentioned were not good ideas and disclaimed as such in the documentation. --- .../lib/active_record/validations/uniqueness.rb | 42 +++++++++------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index cb1d2ae421..a25558bd80 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -154,33 +154,25 @@ module ActiveRecord # | # title! # # This could even happen if you use transactions with the 'serializable' - # isolation level. There are several ways to get around this problem: + # isolation level. The best way to work around this problem is to add a unique + # index to the database table using + # ActiveRecord::ConnectionAdapters::SchemaStatements#add_index. In the + # rare case that a race condition occurs, the database will guarantee + # the field's uniqueness. # - # - By locking the database table before validating, and unlocking it after - # saving. However, table locking is very expensive, and thus not - # recommended. - # - By locking a lock file before validating, and unlocking it after saving. - # This does not work if you've scaled your Rails application across - # multiple web servers (because they cannot share lock files, or cannot - # do that efficiently), and thus not recommended. - # - Creating a unique index on the field, by using - # ActiveRecord::ConnectionAdapters::SchemaStatements#add_index. In the - # rare case that a race condition occurs, the database will guarantee - # the field's uniqueness. + # When the database catches such a duplicate insertion, + # ActiveRecord::Base#save will raise an ActiveRecord::StatementInvalid + # exception. You can either choose to let this error propagate (which + # will result in the default Rails exception page being shown), or you + # can catch it and restart the transaction (e.g. by telling the user + # that the title already exists, and asking him to re-enter the title). + # This technique is also known as optimistic concurrency control: + # http://en.wikipedia.org/wiki/Optimistic_concurrency_control # - # When the database catches such a duplicate insertion, - # ActiveRecord::Base#save will raise an ActiveRecord::StatementInvalid - # exception. You can either choose to let this error propagate (which - # will result in the default Rails exception page being shown), or you - # can catch it and restart the transaction (e.g. by telling the user - # that the title already exists, and asking him to re-enter the title). - # This technique is also known as optimistic concurrency control: - # http://en.wikipedia.org/wiki/Optimistic_concurrency_control - # - # Active Record currently provides no way to distinguish unique - # index constraint errors from other types of database errors, so you - # will have to parse the (database-specific) exception message to detect - # such a case. + # Active Record currently provides no way to distinguish unique + # index constraint errors from other types of database errors, so you + # will have to parse the (database-specific) exception message to detect + # such a case. # def validates_uniqueness_of(*attr_names) validates_with UniquenessValidator, _merge_attributes(attr_names) -- cgit v1.2.3 From c452d734f202fef3560173cd10701be8ff1a057b Mon Sep 17 00:00:00 2001 From: Denis Odorcic Date: Sat, 23 Oct 2010 00:55:17 -0400 Subject: Fix FileStore cache incorrectly regenerating its key from a pathname when a regexp is used in expire_fragment [#5850 state:committed] Signed-off-by: Santiago Pastorino --- activesupport/lib/active_support/cache/file_store.rb | 7 +++---- activesupport/test/caching_test.rb | 4 ++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 84f6f29572..18182bbb40 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/file/atomic' require 'active_support/core_ext/string/conversions' +require 'rack/utils' module ActiveSupport module Cache @@ -11,8 +12,6 @@ module ActiveSupport attr_reader :cache_path DIR_FORMATTER = "%03X" - ESCAPE_FILENAME_CHARS = /[^a-z0-9_.-]/i - UNESCAPE_FILENAME_CHARS = /%[0-9A-F]{2}/ def initialize(cache_path, options = nil) super(options) @@ -136,7 +135,7 @@ module ActiveSupport # Translate a key into a file path. def key_file_path(key) - fname = key.to_s.gsub(ESCAPE_FILENAME_CHARS){|match| "%#{match.ord.to_s(16).upcase}"} + fname = Rack::Utils.escape(key) hash = Zlib.adler32(fname) hash, dir_1 = hash.divmod(0x1000) dir_2 = hash.modulo(0x1000) @@ -156,7 +155,7 @@ module ActiveSupport # Translate a file path into a key. def file_path_key(path) fname = path[cache_path.size, path.size].split(File::SEPARATOR, 4).last - fname.gsub(UNESCAPE_FILENAME_CHARS){|match| $1.ord.to_s(16)} + Rack::Utils.unescape(fname) end # Delete empty directories in the cache. diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index 28ef695a4b..6c178a479f 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -356,9 +356,13 @@ module CacheDeleteMatchedBehavior def test_delete_matched @cache.write("foo", "bar") @cache.write("fu", "baz") + @cache.write("foo/bar", "baz") + @cache.write("fu/baz", "bar") @cache.delete_matched(/oo/) assert_equal false, @cache.exist?("foo") assert_equal true, @cache.exist?("fu") + assert_equal false, @cache.exist?("foo/bar") + assert_equal true, @cache.exist?("fu/baz") end end -- cgit v1.2.3 From 4e0477c9b75683372f662a614ae91b158120ebe8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 7 Nov 2010 20:01:18 -0200 Subject: Test cache.key_file_path with separators ht. Jim Wilson [#5611] --- activesupport/test/caching_test.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index 6c178a479f..579d5dad24 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -513,6 +513,11 @@ class FileStoreTest < ActiveSupport::TestCase assert_nil old_cache.read('foo') end end + + def test_key_transformation + key = @cache.send(:key_file_path, "views/index?id=1") + assert_equal "views/index?id=1", @cache.send(:file_path_key, key) + end end class MemoryStoreTest < ActiveSupport::TestCase -- cgit v1.2.3 From cc135e3b6df1785852de2470b4b93559c88c891e Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Mon, 8 Nov 2010 22:43:51 +0100 Subject: Allow to set dummy application path through options --- .../lib/rails/generators/rails/plugin_new/plugin_new_generator.rb | 5 ++++- railties/test/generators/plugin_new_generator_test.rb | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index d4706063f3..8fac6fc70a 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -102,6 +102,9 @@ task :default => :test alias_method :plugin_path, :app_path + class_option :dummy_path, :type => :string, :default => "test/dummy", + :desc => "Create dummy application at given path" + class_option :full, :type => :boolean, :default => false, :desc => "Generate rails engine with integration tests" @@ -232,7 +235,7 @@ end def dummy_path(path = nil) @dummy_path = path if path - @dummy_path || "test/dummy" + @dummy_path || options[:dummy_path] end def mute(&block) diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index a59013b061..8dc5ca90ba 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -140,6 +140,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "app/helpers/bukkits/application_helper.rb", /module Bukkits\n module ApplicationHelper/ end + def test_passing_dummy_path_as_a_parameter + run_generator [destination_root, "--dummy_path", "spec/dummy"] + assert_file "spec/dummy" + assert_file "spec/dummy/config/application.rb" + assert_no_file "test/dummy" + end + protected def action(*args, &block) -- cgit v1.2.3 From ef46b9f21a275249d1b0cf9926ffb879b0ae2c44 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 9 Nov 2010 05:10:39 +0000 Subject: Strip regexp anchors from rake routes output [#5934 state:resolved] --- actionpack/lib/action_dispatch/routing/route.rb | 3 ++- railties/test/application/rake_test.rb | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/routing/route.rb b/actionpack/lib/action_dispatch/routing/route.rb index f91a48e16c..08a8408f25 100644 --- a/actionpack/lib/action_dispatch/routing/route.rb +++ b/actionpack/lib/action_dispatch/routing/route.rb @@ -30,7 +30,8 @@ module ActionDispatch if method = conditions[:request_method] case method when Regexp - method.source.upcase + source = method.source.upcase + source =~ /\A\^[-A-Z|]+\$\Z/ ? source[1..-2] : source else method.to_s.upcase end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 8e527236ea..719550f9d9 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -38,5 +38,14 @@ module ApplicationTests assert_match "Code LOC: 5 Test LOC: 0 Code to Test Ratio: 1:0.0", Dir.chdir(app_path){ `rake stats` } end + + def test_rake_routes_output_strips_anchors_from_http_verbs + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + get '/cart', :to => 'cart#show' + end + RUBY + assert_match 'cart GET /cart(.:format)', Dir.chdir(app_path){ `rake routes` } + end end end -- cgit v1.2.3 From f57b5197b3215d9dd66196e960ef5d78b7a62de1 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 9 Nov 2010 09:37:32 +0100 Subject: registers number_to_currency's :negative_format in the CHANGELOG --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 2d133ca0b2..b94723c969 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.1.0 (unreleased)* +* The helper number_to_currency accepts a new :negative_format option to be able to configure how to render negative amounts. [Don Wilson] + * Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options: tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)}) -- cgit v1.2.3 From 1f06652a57e727700c3a673dc1f86e3b1e07ce1f Mon Sep 17 00:00:00 2001 From: David Chelimsky Date: Sun, 7 Nov 2010 08:05:18 -0600 Subject: use persisted? instead of new_record? wherever possible - persisted? is the API defined in ActiveModel - makes it easier for extension libraries to conform to ActiveModel APIs without concern for whether the extended object is specifically ActiveRecord [#5927 state:committed] Signed-off-by: Santiago Pastorino --- activerecord/lib/active_record/aggregations.rb | 2 +- activerecord/lib/active_record/associations.rb | 2 +- .../associations/association_collection.rb | 21 +++--- .../associations/association_proxy.rb | 6 +- .../associations/belongs_to_association.rb | 6 +- .../has_and_belongs_to_many_association.rb | 2 +- .../associations/has_many_through_association.rb | 2 +- .../associations/has_one_association.rb | 12 +-- .../associations/has_one_through_association.rb | 2 +- .../active_record/attribute_methods/primary_key.rb | 7 +- .../lib/active_record/autosave_association.rb | 14 ++-- activerecord/lib/active_record/base.rb | 18 +++-- .../lib/active_record/locking/optimistic.rb | 2 +- .../lib/active_record/locking/pessimistic.rb | 2 +- activerecord/lib/active_record/persistence.rb | 12 +-- activerecord/lib/active_record/session_store.rb | 8 +- activerecord/lib/active_record/transactions.rb | 13 ++-- activerecord/lib/active_record/validations.rb | 2 +- .../lib/active_record/validations/uniqueness.rb | 2 +- .../associations/belongs_to_associations_test.rb | 12 +-- .../has_and_belongs_to_many_associations_test.rb | 26 +++---- .../associations/has_many_associations_test.rb | 12 +-- .../associations/has_one_associations_test.rb | 4 +- .../test/cases/associations/join_model_test.rb | 16 ++-- .../test/cases/autosave_association_test.rb | 86 +++++++++++----------- activerecord/test/cases/base_test.rb | 12 +-- activerecord/test/cases/finder_test.rb | 42 +++++------ activerecord/test/cases/nested_attributes_test.rb | 16 ++-- activerecord/test/cases/relations_test.rb | 10 +-- .../test/cases/session_store/sql_bypass.rb | 4 +- activerecord/test/cases/transactions_test.rb | 16 ++-- activerecord/test/models/eye.rb | 2 +- activerecord/test/models/pirate.rb | 2 +- activerecord/test/models/subject.rb | 2 +- activerecord/test/models/topic.rb | 2 +- 35 files changed, 203 insertions(+), 196 deletions(-) diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 16206c1056..8cd7389005 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -6,7 +6,7 @@ module ActiveRecord def clear_aggregation_cache #:nodoc: self.class.reflect_on_all_aggregations.to_a.each do |assoc| instance_variable_set "@#{assoc.name}", nil - end unless self.new_record? + end if self.persisted? end # Active Record implements aggregation through a macro-like class method called +composed_of+ diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index c84673e6a6..08a4ebfd7e 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -118,7 +118,7 @@ module ActiveRecord def clear_association_cache #:nodoc: self.class.reflect_on_all_associations.to_a.each do |assoc| instance_variable_set "@#{assoc.name}", nil - end unless self.new_record? + end if self.persisted? end private diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 896e18af01..398c41f3e9 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -120,13 +120,13 @@ module ActiveRecord # Since << flattens its argument list and inserts each record, +push+ and +concat+ behave identically. def <<(*records) result = true - load_target if @owner.new_record? + load_target unless @owner.persisted? transaction do flatten_deeper(records).each do |record| raise_on_type_mismatch(record) add_record_to_target_with_callbacks(record) do |r| - result &&= insert_record(record) unless @owner.new_record? + result &&= insert_record(record) if @owner.persisted? end end end @@ -285,12 +285,12 @@ module ActiveRecord # This method is abstract in the sense that it relies on # +count_records+, which is a method descendants have to provide. def size - if @owner.new_record? || (loaded? && !@reflection.options[:uniq]) + if !@owner.persisted? || (loaded? && !@reflection.options[:uniq]) @target.size elsif !loaded? && @reflection.options[:group] load_target.size elsif !loaded? && !@reflection.options[:uniq] && @target.is_a?(Array) - unsaved_records = @target.select { |r| r.new_record? } + unsaved_records = @target.reject { |r| r.persisted? } unsaved_records.size + count_records else count_records @@ -357,7 +357,7 @@ module ActiveRecord def include?(record) return false unless record.is_a?(@reflection.klass) - return include_in_memory?(record) if record.new_record? + return include_in_memory?(record) unless record.persisted? load_target if @reflection.options[:finder_sql] && !loaded? return @target.include?(record) if loaded? exists?(record) @@ -372,7 +372,7 @@ module ActiveRecord end def load_target - if !@owner.new_record? || foreign_key_present + if @owner.persisted? || foreign_key_present begin if !loaded? if @target.is_a?(Array) && @target.any? @@ -513,7 +513,7 @@ module ActiveRecord transaction do records.each { |record| callback(:before_remove, record) } - old_records = records.reject { |r| r.new_record? } + old_records = records.select { |r| r.persisted? } yield(records, old_records) records.each { |record| callback(:after_remove, record) } end @@ -538,14 +538,15 @@ module ActiveRecord end def ensure_owner_is_not_new - if @owner.new_record? + unless @owner.persisted? raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved" end end def fetch_first_or_last_using_find?(args) - args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] || - @target.any? { |record| record.new_record? } || args.first.kind_of?(Integer)) + args.first.kind_of?(Hash) || !(loaded? || !@owner.persisted? || @reflection.options[:finder_sql] || + @target.any? { |record| !record.persisted? } || args.first.kind_of?(Integer)) + # TODO - would prefer @target.none? { |r| r.persisted? } end def include_in_memory?(record) diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index ac2aa46edf..09bba213ce 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -175,10 +175,10 @@ module ActiveRecord # If the association is polymorphic the type of the owner is also set. def set_belongs_to_association_for(record) if @reflection.options[:as] - record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record? + record["#{@reflection.options[:as]}_id"] = @owner.id if @owner.persisted? record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s else - unless @owner.new_record? + if @owner.persisted? primary_key = @reflection.options[:primary_key] || :id record[@reflection.primary_key_name] = @owner.send(primary_key) end @@ -252,7 +252,7 @@ module ActiveRecord def load_target return nil unless defined?(@loaded) - if !loaded? and (!@owner.new_record? || foreign_key_present) + if !loaded? and (@owner.persisted? || foreign_key_present) @target = find_target end diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 34b6cd5576..b624951cd9 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -14,7 +14,7 @@ module ActiveRecord counter_cache_name = @reflection.counter_cache_column if record.nil? - if counter_cache_name && !@owner.new_record? + if counter_cache_name && @owner.persisted? @reflection.klass.decrement_counter(counter_cache_name, previous_record_id) if @owner[@reflection.primary_key_name] end @@ -22,13 +22,13 @@ module ActiveRecord else raise_on_type_mismatch(record) - if counter_cache_name && !@owner.new_record? && record.id != @owner[@reflection.primary_key_name] + if counter_cache_name && @owner.persisted? && record.id != @owner[@reflection.primary_key_name] @reflection.klass.increment_counter(counter_cache_name, record.id) @reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name] end @target = (AssociationProxy === record ? record.target : record) - @owner[@reflection.primary_key_name] = record_id(record) unless record.new_record? + @owner[@reflection.primary_key_name] = record_id(record) if record.persisted? @updated = true end diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb index 1fc9aba5cf..da742fa668 100644 --- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb +++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb @@ -34,7 +34,7 @@ module ActiveRecord end def insert_record(record, force = true, validate = true) - if record.new_record? + unless record.persisted? if force record.save! else diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 437c8b1fd6..51770cff0f 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -59,7 +59,7 @@ module ActiveRecord end def insert_record(record, force = true, validate = true) - if record.new_record? + unless record.persisted? if force record.save! else diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 17901387e9..e6e037441f 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -30,18 +30,18 @@ module ActiveRecord if dependent? && !dont_save case @reflection.options[:dependent] when :delete - @target.delete unless @target.new_record? + @target.delete if @target.persisted? @owner.clear_association_cache when :destroy - @target.destroy unless @target.new_record? + @target.destroy if @target.persisted? @owner.clear_association_cache when :nullify @target[@reflection.primary_key_name] = nil - @target.save unless @owner.new_record? || @target.new_record? + @target.save if @owner.persisted? && @target.persisted? end else @target[@reflection.primary_key_name] = nil - @target.save unless @owner.new_record? || @target.new_record? + @target.save if @owner.persisted? && @target.persisted? end end @@ -56,7 +56,7 @@ module ActiveRecord set_inverse_instance(obj, @owner) @loaded = true - unless @owner.new_record? or obj.nil? or dont_save + unless !@owner.persisted? or obj.nil? or dont_save return (obj.save ? self : false) else return (obj.nil? ? nil : self) @@ -113,7 +113,7 @@ module ActiveRecord if replace_existing replace(record, true) else - record[@reflection.primary_key_name] = @owner.id unless @owner.new_record? + record[@reflection.primary_key_name] = @owner.id if @owner.persisted? self.target = record set_inverse_instance(record, @owner) end diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb index 7f28abf464..6e98f7dffb 100644 --- a/activerecord/lib/active_record/associations/has_one_through_association.rb +++ b/activerecord/lib/active_record/associations/has_one_through_association.rb @@ -21,7 +21,7 @@ module ActiveRecord if current_object new_value ? current_object.update_attributes(construct_join_attributes(new_value)) : current_object.destroy elsif new_value - if @owner.new_record? + unless @owner.persisted? self.target = new_value through_association = @owner.send(:association_instance_get, @reflection.through_reflection.name) through_association.build(construct_join_attributes(new_value)) diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 82d94b848a..75ae06f5e9 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -3,10 +3,11 @@ module ActiveRecord module PrimaryKey extend ActiveSupport::Concern - # Returns this record's primary key value wrapped in an Array - # or nil if the record is a new_record? + # Returns this record's primary key value wrapped in an Array or nil if + # the record is not persisted? or has just been destroyed. def to_key - new_record? ? nil : [ id ] + key = send(self.class.primary_key) + [key] if key end module ClassMethods diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 0b89a49896..cb5bc06580 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -217,7 +217,7 @@ module ActiveRecord # Returns whether or not this record has been changed in any way (including whether # any of its nested autosave associations are likewise changed) def changed_for_autosave? - new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave? + !persisted? || changed? || marked_for_destruction? || nested_records_changed_for_autosave? end private @@ -231,7 +231,7 @@ module ActiveRecord elsif autosave association.target.find_all { |record| record.changed_for_autosave? } else - association.target.find_all { |record| record.new_record? } + association.target.find_all { |record| !record.persisted? } end end @@ -257,7 +257,7 @@ module ActiveRecord # +reflection+. def validate_collection_association(reflection) if association = association_instance_get(reflection.name) - if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave]) + if records = associated_records_to_validate_or_save(association, !persisted?, reflection.options[:autosave]) records.each { |record| association_valid?(reflection, record) } end end @@ -286,7 +286,7 @@ module ActiveRecord # Is used as a before_save callback to check while saving a collection # association whether or not the parent was a new record before saving. def before_save_collection_association - @new_record_before_save = new_record? + @new_record_before_save = !persisted? true end @@ -308,7 +308,7 @@ module ActiveRecord if autosave && record.marked_for_destruction? association.destroy(record) - elsif autosave != false && (@new_record_before_save || record.new_record?) + elsif autosave != false && (@new_record_before_save || !record.persisted?) if autosave saved = association.send(:insert_record, record, false, false) else @@ -343,7 +343,7 @@ module ActiveRecord association.destroy else key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id - if autosave != false && (new_record? || association.new_record? || association[reflection.primary_key_name] != key || autosave) + if autosave != false && (!persisted? || !association.persisted? || association[reflection.primary_key_name] != key || autosave) association[reflection.primary_key_name] = key saved = association.save(:validate => !autosave) raise ActiveRecord::Rollback if !saved && autosave @@ -363,7 +363,7 @@ module ActiveRecord if autosave && association.marked_for_destruction? association.destroy elsif autosave != false - saved = association.save(:validate => !autosave) if association.new_record? || autosave + saved = association.save(:validate => !autosave) if !association.persisted? || autosave if association.updated? association_id = association.send(reflection.options[:primary_key] || :id) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 06a388cd21..3e295eeaae 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -204,7 +204,7 @@ module ActiveRecord #:nodoc: # # # No 'Winter' tag exists # winter = Tag.find_or_initialize_by_name("Winter") - # winter.new_record? # true + # winter.persisted? # false # # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of # a list of parameters. @@ -1368,7 +1368,7 @@ MSG def initialize(attributes = nil) @attributes = attributes_from_column_definition @attributes_cache = {} - @new_record = true + @persited = false @readonly = false @destroyed = false @marked_for_destruction = false @@ -1403,7 +1403,7 @@ MSG clear_aggregation_cache clear_association_cache @attributes_cache = {} - @new_record = true + @persisted = false ensure_proper_type populate_with_current_scope_attributes @@ -1422,7 +1422,8 @@ MSG def init_with(coder) @attributes = coder['attributes'] @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {} - @new_record = @readonly = @destroyed = @marked_for_destruction = false + @readonly = @destroyed = @marked_for_destruction = false + @persisted = true _run_find_callbacks _run_initialize_callbacks end @@ -1463,7 +1464,7 @@ MSG # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available) def cache_key case - when new_record? + when !persisted? "#{self.class.model_name.cache_key}/new" when timestamp = self[:updated_at] "#{self.class.model_name.cache_key}/#{id}-#{timestamp.to_s(:number)}" @@ -1584,8 +1585,9 @@ MSG # Returns true if the +comparison_object+ is the same object, or is of the same type and has the same id. def ==(comparison_object) comparison_object.equal?(self) || - (comparison_object.instance_of?(self.class) && - comparison_object.id == id && !comparison_object.new_record?) + persisted? && + (comparison_object.instance_of?(self.class) && + comparison_object.id == id) end # Delegates to == @@ -1630,7 +1632,7 @@ MSG # Returns the contents of the record as a nicely formatted string. def inspect attributes_as_nice_string = self.class.column_names.collect { |name| - if has_attribute?(name) || new_record? + if has_attribute?(name) || !persisted? "#{name}: #{attribute_for_inspect(name)}" end }.compact.join(", ") diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index b6f87a57b8..bf626301f1 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -109,7 +109,7 @@ module ActiveRecord def destroy #:nodoc: return super unless locking_enabled? - unless new_record? + if persisted? lock_col = self.class.locking_column previous_value = send(lock_col).to_i diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb index 9ad6a2baf7..d900831e13 100644 --- a/activerecord/lib/active_record/locking/pessimistic.rb +++ b/activerecord/lib/active_record/locking/pessimistic.rb @@ -47,7 +47,7 @@ module ActiveRecord # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns # the locked record. def lock!(lock = true) - reload(:lock => lock) unless new_record? + reload(:lock => lock) if persisted? self end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 707c1a05be..f905b7026b 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -4,7 +4,8 @@ module ActiveRecord # Returns true if this object hasn't been saved yet -- that is, a record # for the object doesn't exist in the data store yet; otherwise, returns false. def new_record? - @new_record + @persisted = false unless defined?(@persisted) + !@persisted end # Returns true if this object has been destroyed, otherwise returns false. @@ -15,7 +16,8 @@ module ActiveRecord # Returns if the record is persisted, i.e. it's not a new record and it was # not destroyed. def persisted? - !(new_record? || destroyed?) + @persisted = false unless defined?(@persisted) + !!@persisted && !destroyed? end # Saves the model. @@ -94,7 +96,7 @@ module ActiveRecord became = klass.new became.instance_variable_set("@attributes", @attributes) became.instance_variable_set("@attributes_cache", @attributes_cache) - became.instance_variable_set("@new_record", new_record?) + became.instance_variable_set("@persisted", persisted?) became.instance_variable_set("@destroyed", destroyed?) became end @@ -240,7 +242,7 @@ module ActiveRecord private def create_or_update raise ReadOnlyRecord if readonly? - result = new_record? ? create : update + result = persisted? ? update : create result != false end @@ -269,7 +271,7 @@ module ActiveRecord self.id ||= new_id - @new_record = false + @persisted = true id end diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb index 3fc596e02a..a64c5f80c9 100644 --- a/activerecord/lib/active_record/session_store.rb +++ b/activerecord/lib/active_record/session_store.rb @@ -228,7 +228,7 @@ module ActiveRecord @session_id = attributes[:session_id] @data = attributes[:data] @marshaled_data = attributes[:marshaled_data] - @new_record = @marshaled_data.nil? + @persisted = !@marshaled_data.nil? end # Lazy-unmarshal session state. @@ -252,8 +252,8 @@ module ActiveRecord marshaled_data = self.class.marshal(data) connect = connection - if @new_record - @new_record = false + unless @persisted + @persisted = true connect.update <<-end_sql, 'Create session' INSERT INTO #{table_name} ( #{connect.quote_column_name(session_id_column)}, @@ -272,7 +272,7 @@ module ActiveRecord end def destroy - return if @new_record + return unless @persisted connect = connection connect.delete <<-end_sql, 'Destroy session' diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index ab737f0f88..851ec62381 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -242,7 +242,7 @@ module ActiveRecord with_transaction_returning_status { super } end - # Reset id and @new_record if the transaction rolls back. + # Reset id and @persisted if the transaction rolls back. def rollback_active_record_state! remember_transaction_record_state yield @@ -297,9 +297,10 @@ module ActiveRecord # Save the new record state and id of a record so it can be restored later if a transaction fails. def remember_transaction_record_state #:nodoc @_start_transaction_state ||= {} - unless @_start_transaction_state.include?(:new_record) + unless @_start_transaction_state.include?(:persisted) @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key) - @_start_transaction_state[:new_record] = @new_record + @persisted = false unless defined?(@persisted) + @_start_transaction_state[:persisted] = @persisted end unless @_start_transaction_state.include?(:destroyed) @_start_transaction_state[:destroyed] = @destroyed @@ -323,7 +324,7 @@ module ActiveRecord restore_state = remove_instance_variable(:@_start_transaction_state) if restore_state @attributes = @attributes.dup if @attributes.frozen? - @new_record = restore_state[:new_record] + @persisted = restore_state[:persisted] @destroyed = restore_state[:destroyed] if restore_state[:id] self.id = restore_state[:id] @@ -345,11 +346,11 @@ module ActiveRecord def transaction_include_action?(action) #:nodoc case action when :create - transaction_record_state(:new_record) + transaction_record_state(:new_record) || !transaction_record_state(:persisted) when :destroy destroyed? when :update - !(transaction_record_state(:new_record) || destroyed?) + !(transaction_record_state(:new_record) || !transaction_record_state(:persisted) || destroyed?) end end end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index f367315b22..ee45fcdf35 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -51,7 +51,7 @@ module ActiveRecord # Runs all the specified validations and returns true if no errors were added otherwise false. def valid?(context = nil) - context ||= (new_record? ? :create : :update) + context ||= (persisted? ? :update : :create) output = super(context) errors.empty? && output end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index a25558bd80..3eba7510ac 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -31,7 +31,7 @@ module ActiveRecord relation = relation.where(scope_item => scope_value) end - unless record.new_record? + if record.persisted? # TODO : This should be in Arel relation = relation.where("#{record.class.quoted_table_name}.#{record.class.primary_key} <> ?", record.send(:id)) end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 0fa4328826..1b0c00bd5a 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -285,10 +285,10 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase final_cut = Client.new("name" => "Final Cut") firm = Firm.find(1) final_cut.firm = firm - assert final_cut.new_record? + assert !final_cut.persisted? assert final_cut.save - assert !final_cut.new_record? - assert !firm.new_record? + assert final_cut.persisted? + assert firm.persisted? assert_equal firm, final_cut.firm assert_equal firm, final_cut.firm(true) end @@ -297,10 +297,10 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase final_cut = Client.new("name" => "Final Cut") firm = Firm.find(1) final_cut.firm_with_primary_key = firm - assert final_cut.new_record? + assert !final_cut.persisted? assert final_cut.save - assert !final_cut.new_record? - assert !firm.new_record? + assert final_cut.persisted? + assert firm.persisted? assert_equal firm, final_cut.firm_with_primary_key assert_equal firm, final_cut.firm_with_primary_key(true) 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 7e070e1746..c55523de38 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 @@ -251,10 +251,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase no_of_projects = Project.count aredridel = Developer.new("name" => "Aredridel") aredridel.projects.concat([Project.find(1), p = Project.new("name" => "Projekt")]) - assert aredridel.new_record? - assert p.new_record? + assert !aredridel.persisted? + assert !p.persisted? assert aredridel.save - assert !aredridel.new_record? + assert aredridel.persisted? assert_equal no_of_devels+1, Developer.count assert_equal no_of_projects+1, Project.count assert_equal 2, aredridel.projects.size @@ -288,9 +288,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal devel.projects.last, proj assert devel.projects.loaded? - assert proj.new_record? + assert !proj.persisted? devel.save - assert !proj.new_record? + assert proj.persisted? assert_equal devel.projects.last, proj assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated end @@ -300,10 +300,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase proj1 = devel.projects.build(:name => "Make bed") proj2 = devel.projects.build(:name => "Lie in it") assert_equal devel.projects.last, proj2 - assert proj2.new_record? + assert !proj2.persisted? devel.save - assert !devel.new_record? - assert !proj2.new_record? + assert devel.persisted? + assert proj2.persisted? assert_equal devel.projects.last, proj2 assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated end @@ -316,7 +316,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal devel.projects.last, proj assert !devel.projects.loaded? - assert !proj.new_record? + assert proj.persisted? assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated end @@ -325,10 +325,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase proj1 = devel.projects.build(:name => "Make bed") proj2 = devel.projects.build(:name => "Lie in it") assert_equal devel.projects.last, proj2 - assert proj2.new_record? + assert !proj2.persisted? devel.save - assert !devel.new_record? - assert !proj2.new_record? + assert devel.persisted? + assert proj2.persisted? assert_equal devel.projects.last, proj2 assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated end @@ -343,7 +343,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase # 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 another_post.persisted? assert_equal 'Yet Another Testing Title', another_post.title end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index c9f00fd737..e9c119b823 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -187,7 +187,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase another = author.posts.find_or_create_by_title_and_body("Another Post", "This is the Body") assert_equal number_of_posts + 1, Post.count assert_equal another, author.posts.find_or_create_by_title_and_body("Another Post", "This is the Body") - assert !another.new_record? + assert another.persisted? end def test_cant_save_has_many_readonly_association @@ -453,7 +453,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name - assert new_client.new_record? + assert !new_client.persisted? assert_equal new_client, company.clients_of_firm.last end @@ -508,7 +508,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name - assert new_client.new_record? + assert !new_client.persisted? assert_equal new_client, company.clients_of_firm.last end @@ -543,7 +543,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_create force_signal37_to_load_all_clients_of_firm new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client") - assert !new_client.new_record? + assert new_client.persisted? assert_equal new_client, companies(:first_firm).clients_of_firm.last assert_equal new_client, companies(:first_firm).clients_of_firm(true).last end @@ -563,7 +563,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase the_client = companies(:first_firm).clients.find_or_initialize_by_name("Yet another client") assert_equal companies(:first_firm).id, the_client.firm_id assert_equal "Yet another client", the_client.name - assert the_client.new_record? + assert !the_client.persisted? end def test_find_or_create_updates_size @@ -752,7 +752,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create - assert !another_ms_client.new_record? + assert another_ms_client.persisted? assert_equal 'Microsoft', another_ms_client.name end diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index b522be3fe0..6fbeff8aa9 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -268,7 +268,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_assignment_before_child_saved firm = Firm.find(1) firm.account = a = Account.new("credit_limit" => 1000) - assert !a.new_record? + assert a.persisted? assert_equal a, firm.account assert_equal a, firm.account assert_equal a, firm.account(true) @@ -323,7 +323,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_create_respects_hash_condition account = companies(:first_firm).create_account_limit_500_with_hash_conditions - assert !account.new_record? + assert account.persisted? assert_equal 500, account.credit_limit end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 7a22ce4dad..96edcfbb35 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -450,11 +450,11 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase new_tag = Tag.new(:name => "new") saved_post.tags << new_tag - assert !new_tag.new_record? #consistent with habtm! - assert !saved_post.new_record? + assert new_tag.persisted? #consistent with habtm! + assert saved_post.persisted? assert saved_post.tags.include?(new_tag) - assert !new_tag.new_record? + assert new_tag.persisted? assert saved_post.reload.tags(true).include?(new_tag) @@ -462,16 +462,16 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase saved_tag = tags(:general) new_post.tags << saved_tag - assert new_post.new_record? - assert !saved_tag.new_record? + assert !new_post.persisted? + assert saved_tag.persisted? assert new_post.tags.include?(saved_tag) new_post.save! - assert !new_post.new_record? + assert new_post.persisted? assert new_post.reload.tags(true).include?(saved_tag) - assert posts(:thinking).tags.build.new_record? - assert posts(:thinking).tags.new.new_record? + assert !posts(:thinking).tags.build.persisted? + assert !posts(:thinking).tags.new.persisted? end def test_create_associate_when_adding_to_has_many_through diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 89be94c81f..459f9fa55c 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -83,7 +83,7 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas assert !firm.build_account_using_primary_key.valid? assert firm.save - assert firm.account_using_primary_key.new_record? + assert !firm.account_using_primary_key.persisted? end def test_save_fails_for_invalid_has_one @@ -114,10 +114,10 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas account = firm.account.build("credit_limit" => 1000) assert_equal account, firm.account - assert account.new_record? + assert !account.persisted? assert firm.save assert_equal account, firm.account - assert !account.new_record? + assert account.persisted? end def test_build_before_either_saved @@ -125,16 +125,16 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas firm.account = account = Account.new("credit_limit" => 1000) assert_equal account, firm.account - assert account.new_record? + assert !account.persisted? assert firm.save assert_equal account, firm.account - assert !account.new_record? + assert account.persisted? end def test_assignment_before_parent_saved firm = Firm.new("name" => "GlobalMegaCorp") firm.account = a = Account.find(1) - assert firm.new_record? + assert !firm.persisted? assert_equal a, firm.account assert firm.save assert_equal a, firm.account @@ -144,12 +144,12 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas def test_assignment_before_either_saved firm = Firm.new("name" => "GlobalMegaCorp") firm.account = a = Account.new("credit_limit" => 1000) - assert firm.new_record? - assert a.new_record? + assert !firm.persisted? + assert !a.persisted? assert_equal a, firm.account assert firm.save - assert !firm.new_record? - assert !a.new_record? + assert firm.persisted? + assert a.persisted? assert_equal a, firm.account assert_equal a, firm.account(true) end @@ -203,7 +203,7 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test assert !client.firm.valid? assert client.save - assert client.firm.new_record? + assert !client.firm.persisted? end def test_save_fails_for_invalid_belongs_to @@ -232,10 +232,10 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test apple = Firm.new("name" => "Apple") client.firm = apple assert_equal apple, client.firm - assert apple.new_record? + assert !apple.persisted? assert client.save assert apple.save - assert !apple.new_record? + assert apple.persisted? assert_equal apple, client.firm assert_equal apple, client.firm(true) end @@ -244,11 +244,11 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test final_cut = Client.new("name" => "Final Cut") apple = Firm.new("name" => "Apple") final_cut.firm = apple - assert final_cut.new_record? - assert apple.new_record? + assert !final_cut.persisted? + assert !apple.persisted? assert final_cut.save - assert !final_cut.new_record? - assert !apple.new_record? + assert final_cut.persisted? + assert apple.persisted? assert_equal apple, final_cut.firm assert_equal apple, final_cut.firm(true) end @@ -348,10 +348,10 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_invalid_adding firm = Firm.find(1) assert !(firm.clients_of_firm << c = Client.new) - assert c.new_record? + assert !c.persisted? assert !firm.valid? assert !firm.save - assert c.new_record? + assert !c.persisted? end def test_invalid_adding_before_save @@ -359,12 +359,12 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa no_of_clients = Client.count new_firm = Firm.new("name" => "A New Firm, Inc") new_firm.clients_of_firm.concat([c = Client.new, Client.new("name" => "Apple")]) - assert c.new_record? + assert !c.persisted? assert !c.valid? assert !new_firm.valid? assert !new_firm.save - assert c.new_record? - assert new_firm.new_record? + assert !c.persisted? + assert !new_firm.persisted? end def test_invalid_adding_with_validate_false @@ -375,7 +375,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert firm.valid? assert !client.valid? assert firm.save - assert client.new_record? + assert !client.persisted? end def test_valid_adding_with_validate_false @@ -386,22 +386,22 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert firm.valid? assert client.valid? - assert client.new_record? + assert !client.persisted? firm.unvalidated_clients_of_firm << client assert firm.save - assert !client.new_record? + assert client.persisted? assert_equal no_of_clients + 1, Client.count end def test_invalid_build new_client = companies(:first_firm).clients_of_firm.build - assert new_client.new_record? + assert !new_client.persisted? assert !new_client.valid? assert_equal new_client, companies(:first_firm).clients_of_firm.last assert !companies(:first_firm).save - assert new_client.new_record? + assert !new_client.persisted? assert_equal 1, companies(:first_firm).clients_of_firm(true).size end @@ -420,8 +420,8 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert_equal no_of_firms, Firm.count # Firm was not saved to database. assert_equal no_of_clients, Client.count # Clients were not saved to database. assert new_firm.save - assert !new_firm.new_record? - assert !c.new_record? + assert new_firm.persisted? + assert c.persisted? assert_equal new_firm, c.firm assert_equal no_of_firms + 1, Firm.count # Firm was saved to database. assert_equal no_of_clients + 2, Client.count # Clients were saved to database. @@ -455,7 +455,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa company.name += '-changed' assert_queries(2) { assert company.save } - assert !new_client.new_record? + assert new_client.persisted? assert_equal 2, company.clients_of_firm(true).size end @@ -475,7 +475,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa company.name += '-changed' assert_queries(2) { assert company.save } - assert !new_client.new_record? + assert new_client.persisted? assert_equal 2, company.clients_of_firm(true).size end @@ -507,62 +507,62 @@ class TestDefaultAutosaveAssociationOnNewRecord < ActiveRecord::TestCase new_account = Account.new("credit_limit" => 1000) new_firm = Firm.new("name" => "some firm") - assert new_firm.new_record? + assert !new_firm.persisted? new_account.firm = new_firm new_account.save! - assert !new_firm.new_record? + assert new_firm.persisted? new_account = Account.new("credit_limit" => 1000) new_autosaved_firm = Firm.new("name" => "some firm") - assert new_autosaved_firm.new_record? + assert !new_autosaved_firm.persisted? new_account.unautosaved_firm = new_autosaved_firm new_account.save! - assert new_autosaved_firm.new_record? + assert !new_autosaved_firm.persisted? end def test_autosave_new_record_on_has_one_can_be_disabled_per_relationship firm = Firm.new("name" => "some firm") account = Account.new("credit_limit" => 1000) - assert account.new_record? + assert !account.persisted? firm.account = account firm.save! - assert !account.new_record? + assert account.persisted? firm = Firm.new("name" => "some firm") account = Account.new("credit_limit" => 1000) firm.unautosaved_account = account - assert account.new_record? + assert !account.persisted? firm.unautosaved_account = account firm.save! - assert account.new_record? + assert !account.persisted? end def test_autosave_new_record_on_has_many_can_be_disabled_per_relationship firm = Firm.new("name" => "some firm") account = Account.new("credit_limit" => 1000) - assert account.new_record? + assert !account.persisted? firm.accounts << account firm.save! - assert !account.new_record? + assert account.persisted? firm = Firm.new("name" => "some firm") account = Account.new("credit_limit" => 1000) - assert account.new_record? + assert !account.persisted? firm.unautosaved_accounts << account firm.save! - assert account.new_record? + assert !account.persisted? end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index ceb1272862..9f2b0c9c86 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -656,8 +656,8 @@ class BasicsTest < ActiveRecord::TestCase end def test_new_record_returns_boolean - assert_equal true, Topic.new.new_record? - assert_equal false, Topic.find(1).new_record? + assert_equal false, Topic.new.persisted? + assert_equal true, Topic.find(1).persisted? end def test_clone @@ -665,7 +665,7 @@ class BasicsTest < ActiveRecord::TestCase cloned_topic = nil assert_nothing_raised { cloned_topic = topic.clone } assert_equal topic.title, cloned_topic.title - assert cloned_topic.new_record? + assert !cloned_topic.persisted? # test if the attributes have been cloned topic.title = "a" @@ -684,7 +684,7 @@ class BasicsTest < ActiveRecord::TestCase # test if saved clone object differs from original cloned_topic.save - assert !cloned_topic.new_record? + assert cloned_topic.persisted? assert_not_equal cloned_topic.id, topic.id cloned_topic.reload @@ -700,7 +700,7 @@ class BasicsTest < ActiveRecord::TestCase assert_nothing_raised { clone = dev.clone } assert_kind_of DeveloperSalary, clone.salary assert_equal dev.salary.amount, clone.salary.amount - assert clone.new_record? + assert !clone.persisted? # test if the attributes have been cloned original_amount = clone.salary.amount @@ -708,7 +708,7 @@ class BasicsTest < ActiveRecord::TestCase assert_equal original_amount, clone.salary.amount assert clone.save - assert !clone.new_record? + assert clone.persisted? assert_not_equal clone.id, dev.id end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index c058196078..87ec999b03 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -726,7 +726,7 @@ class FinderTest < ActiveRecord::TestCase sig38 = Company.find_or_create_by_name("38signals") assert_equal number_of_companies + 1, Company.count assert_equal sig38, Company.find_or_create_by_name("38signals") - assert !sig38.new_record? + assert sig38.persisted? end def test_find_or_create_from_two_attributes @@ -734,7 +734,7 @@ class FinderTest < ActiveRecord::TestCase another = Topic.find_or_create_by_title_and_author_name("Another topic","John") assert_equal number_of_topics + 1, Topic.count assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John") - assert !another.new_record? + assert another.persisted? end def test_find_or_create_from_two_attributes_with_one_being_an_aggregate @@ -742,7 +742,7 @@ class FinderTest < ActiveRecord::TestCase created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth") assert_equal number_of_customers + 1, Customer.count assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth") - assert !created_customer.new_record? + assert created_customer.persisted? end def test_find_or_create_from_one_attribute_and_hash @@ -750,7 +750,7 @@ class FinderTest < ActiveRecord::TestCase sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23}) assert_equal number_of_companies + 1, Company.count assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23}) - assert !sig38.new_record? + assert sig38.persisted? assert_equal "38signals", sig38.name assert_equal 17, sig38.firm_id assert_equal 23, sig38.client_of @@ -761,7 +761,7 @@ class FinderTest < ActiveRecord::TestCase created_customer = Customer.find_or_create_by_balance(Money.new(123)) assert_equal number_of_customers + 1, Customer.count assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123)) - assert !created_customer.new_record? + assert created_customer.persisted? end def test_find_or_create_from_one_aggregate_attribute_and_hash @@ -771,7 +771,7 @@ class FinderTest < ActiveRecord::TestCase created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name}) assert_equal number_of_customers + 1, Customer.count assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name}) - assert !created_customer.new_record? + assert created_customer.persisted? assert_equal balance, created_customer.balance assert_equal name, created_customer.name end @@ -779,13 +779,13 @@ class FinderTest < ActiveRecord::TestCase def test_find_or_initialize_from_one_attribute sig38 = Company.find_or_initialize_by_name("38signals") assert_equal "38signals", sig38.name - assert sig38.new_record? + assert !sig38.persisted? end def test_find_or_initialize_from_one_aggregate_attribute new_customer = Customer.find_or_initialize_by_balance(Money.new(123)) assert_equal 123, new_customer.balance.amount - assert new_customer.new_record? + assert !new_customer.persisted? end def test_find_or_initialize_from_one_attribute_should_not_set_attribute_even_when_protected @@ -793,7 +793,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_not_equal 1000, c.rating assert c.valid? - assert c.new_record? + assert !c.persisted? end def test_find_or_create_from_one_attribute_should_not_set_attribute_even_when_protected @@ -801,7 +801,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_not_equal 1000, c.rating assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected @@ -809,7 +809,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000, c.rating assert c.valid? - assert c.new_record? + assert !c.persisted? end def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected @@ -817,7 +817,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000, c.rating assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash @@ -825,7 +825,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000, c.rating assert c.valid? - assert c.new_record? + assert !c.persisted? end def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash @@ -833,7 +833,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000, c.rating assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_initialize_should_set_protected_attributes_if_given_as_block @@ -841,7 +841,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000.to_f, c.rating.to_f assert c.valid? - assert c.new_record? + assert !c.persisted? end def test_find_or_create_should_set_protected_attributes_if_given_as_block @@ -849,7 +849,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000.to_f, c.rating.to_f assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_create_should_work_with_block_on_first_call @@ -860,21 +860,21 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000.to_f, c.rating.to_f assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_initialize_from_two_attributes another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John") assert_equal "Another topic", another.title assert_equal "John", another.author_name - assert another.new_record? + assert !another.persisted? end def test_find_or_initialize_from_one_aggregate_attribute_and_one_not new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth") assert_equal 123, new_customer.balance.amount assert_equal "Elizabeth", new_customer.name - assert new_customer.new_record? + assert !new_customer.persisted? end def test_find_or_initialize_from_one_attribute_and_hash @@ -882,7 +882,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "38signals", sig38.name assert_equal 17, sig38.firm_id assert_equal 23, sig38.client_of - assert sig38.new_record? + assert !sig38.persisted? end def test_find_or_initialize_from_one_aggregate_attribute_and_hash @@ -891,7 +891,7 @@ class FinderTest < ActiveRecord::TestCase new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name}) assert_equal balance, new_customer.balance assert_equal name, new_customer.name - assert new_customer.new_record? + assert !new_customer.persisted? end def test_find_with_bad_sql diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 60f89da95e..765f59e0ac 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -163,7 +163,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase @ship.destroy @pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' } - assert @pirate.ship.new_record? + assert !@pirate.ship.persisted? assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name end @@ -184,7 +184,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase def test_should_replace_an_existing_record_if_there_is_no_id @pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' } - assert @pirate.ship.new_record? + assert !@pirate.ship.persisted? assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name assert_equal 'Nights Dirty Lightning', @ship.name end @@ -256,7 +256,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase def test_should_also_work_with_a_HashWithIndifferentAccess @pirate.ship_attributes = HashWithIndifferentAccess.new(:id => @ship.id, :name => 'Davy Jones Gold Dagger') - assert !@pirate.ship.new_record? + assert @pirate.ship.persisted? assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name end @@ -348,7 +348,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase @pirate.destroy @ship.reload.pirate_attributes = { :catchphrase => 'Arr' } - assert @ship.pirate.new_record? + assert !@ship.pirate.persisted? assert_equal 'Arr', @ship.pirate.catchphrase end @@ -369,7 +369,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase def test_should_replace_an_existing_record_if_there_is_no_id @ship.reload.pirate_attributes = { :catchphrase => 'Arr' } - assert @ship.pirate.new_record? + assert !@ship.pirate.persisted? assert_equal 'Arr', @ship.pirate.catchphrase assert_equal 'Aye', @pirate.catchphrase end @@ -458,7 +458,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase @pirate.delete @ship.reload.attributes = { :update_only_pirate_attributes => { :catchphrase => 'Arr' } } - assert @ship.update_only_pirate.new_record? + assert !@ship.update_only_pirate.persisted? end def test_should_update_existing_when_update_only_is_true_and_no_id_is_given @@ -596,10 +596,10 @@ module NestedAttributesOnACollectionAssociationTests association_getter => { 'foo' => { :name => 'Grace OMalley' }, 'bar' => { :name => 'Privateers Greed' }} } - assert @pirate.send(@association_name).first.new_record? + assert !@pirate.send(@association_name).first.persisted? assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name - assert @pirate.send(@association_name).last.new_record? + assert !@pirate.send(@association_name).last.persisted? assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 0fd2b99937..b44c716db8 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -383,7 +383,7 @@ class RelationTest < ActiveRecord::TestCase lifo = authors.find_or_initialize_by_name('Lifo') assert_equal "Lifo", lifo.name - assert lifo.new_record? + assert !lifo.persisted? assert_equal authors(:david), authors.find_or_initialize_by_name(:name => 'David') end @@ -393,7 +393,7 @@ class RelationTest < ActiveRecord::TestCase lifo = authors.find_or_create_by_name('Lifo') assert_equal "Lifo", lifo.name - assert ! lifo.new_record? + assert lifo.persisted? assert_equal authors(:david), authors.find_or_create_by_name(:name => 'David') end @@ -627,10 +627,10 @@ class RelationTest < ActiveRecord::TestCase sparrow = birds.create assert_kind_of Bird, sparrow - assert sparrow.new_record? + assert !sparrow.persisted? hen = birds.where(:name => 'hen').create - assert ! hen.new_record? + assert hen.persisted? assert_equal 'hen', hen.name end @@ -641,7 +641,7 @@ class RelationTest < ActiveRecord::TestCase hen = birds.where(:name => 'hen').create! assert_kind_of Bird, hen - assert ! hen.new_record? + assert hen.persisted? assert_equal 'hen', hen.name end diff --git a/activerecord/test/cases/session_store/sql_bypass.rb b/activerecord/test/cases/session_store/sql_bypass.rb index f0ba166465..7402b2afd6 100644 --- a/activerecord/test/cases/session_store/sql_bypass.rb +++ b/activerecord/test/cases/session_store/sql_bypass.rb @@ -18,9 +18,9 @@ module ActiveRecord assert !Session.table_exists? end - def test_new_record? + def test_persisted? s = SqlBypass.new :data => 'foo', :session_id => 10 - assert s.new_record?, 'this is a new record!' + assert !s.persisted?, 'this is a new record!' end def test_not_loaded? diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 0fbcef4091..dd9de3510b 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -182,7 +182,7 @@ class TransactionTest < ActiveRecord::TestCase :bonus_time => "2005-01-30t15:28:00.00+01:00", :content => "Have a nice day", :approved => false) - new_record_snapshot = new_topic.new_record? + new_record_snapshot = !new_topic.persisted? id_present = new_topic.has_attribute?(Topic.primary_key) id_snapshot = new_topic.id @@ -195,7 +195,7 @@ class TransactionTest < ActiveRecord::TestCase flunk rescue => e assert_equal "Make the transaction rollback", e.message - assert_equal new_record_snapshot, new_topic.new_record?, "The topic should have its old new_record value" + assert_equal new_record_snapshot, !new_topic.persisted?, "The topic should have its old persisted value" assert_equal id_snapshot, new_topic.id, "The topic should have its old id" assert_equal id_present, new_topic.has_attribute?(Topic.primary_key) ensure @@ -370,21 +370,21 @@ class TransactionTest < ActiveRecord::TestCase assert topic_2.save @first.save @second.destroy - assert_equal false, topic_1.new_record? + assert_equal true, topic_1.persisted? assert_not_nil topic_1.id - assert_equal false, topic_2.new_record? + assert_equal true, topic_2.persisted? assert_not_nil topic_2.id - assert_equal false, @first.new_record? + assert_equal true, @first.persisted? assert_not_nil @first.id assert_equal true, @second.destroyed? raise ActiveRecord::Rollback end - assert_equal true, topic_1.new_record? + assert_equal false, topic_1.persisted? assert_nil topic_1.id - assert_equal true, topic_2.new_record? + assert_equal false, topic_2.persisted? assert_nil topic_2.id - assert_equal false, @first.new_record? + assert_equal true, @first.persisted? assert_not_nil @first.id assert_equal false, @second.destroyed? end diff --git a/activerecord/test/models/eye.rb b/activerecord/test/models/eye.rb index 77f17b578e..dc8ae2b3f6 100644 --- a/activerecord/test/models/eye.rb +++ b/activerecord/test/models/eye.rb @@ -17,7 +17,7 @@ class Eye < ActiveRecord::Base after_save :trace_after_save2 def trace_after_create - (@after_create_callbacks_stack ||= []) << iris.new_record? + (@after_create_callbacks_stack ||= []) << !iris.persisted? end alias trace_after_create2 trace_after_create diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb index d89c8cf381..f2c45053e7 100644 --- a/activerecord/test/models/pirate.rb +++ b/activerecord/test/models/pirate.rb @@ -48,7 +48,7 @@ class Pirate < ActiveRecord::Base end def reject_empty_ships_on_create(attributes) - attributes.delete('_reject_me_if_new').present? && new_record? + attributes.delete('_reject_me_if_new').present? && !persisted? end attr_accessor :cancel_save_from_callback diff --git a/activerecord/test/models/subject.rb b/activerecord/test/models/subject.rb index d4b8b91de8..8e28f8b86b 100644 --- a/activerecord/test/models/subject.rb +++ b/activerecord/test/models/subject.rb @@ -8,7 +8,7 @@ class Subject < ActiveRecord::Base protected def set_email_address - if self.new_record? + unless self.persisted? self.author_email_address = 'test@test.com' end end diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 82d4b5997f..6496f36f7e 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -89,7 +89,7 @@ class Topic < ActiveRecord::Base end def set_email_address - if self.new_record? + unless self.persisted? self.author_email_address = 'test@test.com' end end -- cgit v1.2.3 From 994a1c2a4747efcca3c6278c119096d93f793da1 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 9 Nov 2010 14:03:09 -0200 Subject: Execute less operations --- activerecord/lib/active_record/associations/association_collection.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 398c41f3e9..71d8c2d3c8 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -545,8 +545,7 @@ module ActiveRecord def fetch_first_or_last_using_find?(args) args.first.kind_of?(Hash) || !(loaded? || !@owner.persisted? || @reflection.options[:finder_sql] || - @target.any? { |record| !record.persisted? } || args.first.kind_of?(Integer)) - # TODO - would prefer @target.none? { |r| r.persisted? } + !@target.all? { |record| record.persisted? } || args.first.kind_of?(Integer)) end def include_in_memory?(record) -- cgit v1.2.3 From 75dfd95618310a9522a73d8126b35351c8189042 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 9 Nov 2010 16:00:02 -0200 Subject: Don't check if persisted is defined just initialize it properly --- activerecord/lib/active_record/base.rb | 2 +- activerecord/lib/active_record/persistence.rb | 2 -- activerecord/lib/active_record/transactions.rb | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 3e295eeaae..f588475bbf 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1368,7 +1368,7 @@ MSG def initialize(attributes = nil) @attributes = attributes_from_column_definition @attributes_cache = {} - @persited = false + @persisted = false @readonly = false @destroyed = false @marked_for_destruction = false diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index f905b7026b..390e09d826 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -4,7 +4,6 @@ module ActiveRecord # Returns true if this object hasn't been saved yet -- that is, a record # for the object doesn't exist in the data store yet; otherwise, returns false. def new_record? - @persisted = false unless defined?(@persisted) !@persisted end @@ -16,7 +15,6 @@ module ActiveRecord # Returns if the record is persisted, i.e. it's not a new record and it was # not destroyed. def persisted? - @persisted = false unless defined?(@persisted) !!@persisted && !destroyed? end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 851ec62381..8c94d1a2bc 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -299,7 +299,6 @@ module ActiveRecord @_start_transaction_state ||= {} unless @_start_transaction_state.include?(:persisted) @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key) - @persisted = false unless defined?(@persisted) @_start_transaction_state[:persisted] = @persisted end unless @_start_transaction_state.include?(:destroyed) -- cgit v1.2.3 From 88a559d4148789474c6dbd216725c69fa18200a9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 9 Nov 2010 16:53:03 -0200 Subject: Double negation of an already boolean value produces the same result --- activerecord/lib/active_record/persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 390e09d826..00d49dd0f6 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -15,7 +15,7 @@ module ActiveRecord # Returns if the record is persisted, i.e. it's not a new record and it was # not destroyed. def persisted? - !!@persisted && !destroyed? + @persisted && !destroyed? end # Saves the model. -- cgit v1.2.3 From 41366cdec6003011e19971c1bcfb82949ff93a6e Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 9 Nov 2010 20:56:41 +0100 Subject: syncs CHANGELOGs for 3.0.2 in 3-0-stable with the ones in master --- actionmailer/CHANGELOG | 4 ++++ actionpack/CHANGELOG | 6 ++++-- activemodel/CHANGELOG | 4 ++++ activerecord/CHANGELOG | 29 +++++++++++++++++++++++++++++ activeresource/CHANGELOG | 4 ++++ activesupport/CHANGELOG | 4 ++++ 6 files changed, 49 insertions(+), 2 deletions(-) diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG index 9c073dce1f..167c1da9c5 100644 --- a/actionmailer/CHANGELOG +++ b/actionmailer/CHANGELOG @@ -2,6 +2,10 @@ * No changes +*Rails 3.0.2 (unreleased)* + +* No changes + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index b94723c969..db02beee35 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,7 +1,5 @@ *Rails 3.1.0 (unreleased)* -* The helper number_to_currency accepts a new :negative_format option to be able to configure how to render negative amounts. [Don Wilson] - * Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options: tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)}) @@ -25,6 +23,10 @@ * Add Rack::Cache to the default stack. Create a Rails store that delegates to the Rails cache, so by default, whatever caching layer you are using will be used for HTTP caching. Note that Rack::Cache will be used if you use #expires_in, #fresh_when or #stale with :public => true. Otherwise, the caching rules will apply to the browser only. [Yehuda Katz, Carl Lerche] +*Rails 3.0.2 (unreleased)* + +* The helper number_to_currency accepts a new :negative_format option to be able to configure how to render negative amounts. [Don Wilson] + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG index e93d84ab59..4e963c77b0 100644 --- a/activemodel/CHANGELOG +++ b/activemodel/CHANGELOG @@ -2,6 +2,10 @@ * No changes +*Rails 3.0.2 (unreleased)* + +* No changes + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index d3530e0da9..11eb47917d 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -18,6 +18,35 @@ [Aaron Patterson] +*Rails 3.0.2 (unreleased)* + +* reorder is deprecated in favor of except(:order).order(...) [Santiago Pastorino] + +* except is now AR public API + + Model.order('name').except(:order).order('salary') + + generates: + + SELECT * FROM models ORDER BY salary + + [Santiago Pastorino] + +* The following code: + + Model.limit(10).scoping { Model.count } + + now generates the following SQL: + + SELECT COUNT(*) FROM models LIMIT 10 + + This may not return what you want. Instead, you may with to do something + like this: + + Model.limit(10).scoping { Model.all.size } + + [Aaron Patterson] + *Rails 3.0.1 (October 15, 2010)* * Introduce a fix for CVE-2010-3993 diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG index 24fe3072e0..386bafd7de 100644 --- a/activeresource/CHANGELOG +++ b/activeresource/CHANGELOG @@ -2,6 +2,10 @@ * No changes +*Rails 3.0.2 (unreleased)* + +* No changes + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 3b6a29f7d6..6e8cce0d27 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -4,6 +4,10 @@ * Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White] +*Rails 3.0.2 (unreleased)* + +* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White] + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. -- cgit v1.2.3 From b961c6c158d31e3648a3239ee6846ab98d027162 Mon Sep 17 00:00:00 2001 From: Denis Odorcic Date: Tue, 9 Nov 2010 23:49:52 -0500 Subject: Remove useless cgi [#5943 state:committed] Signed-off-by: Santiago Pastorino --- activesupport/lib/active_support/core_ext/cgi.rb | 1 - .../core_ext/cgi/escape_skipping_slashes.rb | 19 ------------------- activesupport/test/core_ext/cgi_ext_test.rb | 15 --------------- railties/lib/rails/info.rb | 1 - 4 files changed, 36 deletions(-) delete mode 100644 activesupport/lib/active_support/core_ext/cgi.rb delete mode 100644 activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb delete mode 100644 activesupport/test/core_ext/cgi_ext_test.rb diff --git a/activesupport/lib/active_support/core_ext/cgi.rb b/activesupport/lib/active_support/core_ext/cgi.rb deleted file mode 100644 index 7279a3d4da..0000000000 --- a/activesupport/lib/active_support/core_ext/cgi.rb +++ /dev/null @@ -1 +0,0 @@ -require 'active_support/core_ext/cgi/escape_skipping_slashes' diff --git a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb b/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb deleted file mode 100644 index d3c3575748..0000000000 --- a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'cgi' - -class CGI #:nodoc: - if RUBY_VERSION >= '1.9' - def self.escape_skipping_slashes(str) - str = str.join('/') if str.respond_to? :join - str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do - "%#{$1.unpack('H2' * $1.bytesize).join('%').upcase}" - end.tr(' ', '+') - end - else - def self.escape_skipping_slashes(str) - str = str.join('/') if str.respond_to? :join - str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do - "%#{$1.unpack('H2').first.upcase}" - end.tr(' ', '+') - end - end -end diff --git a/activesupport/test/core_ext/cgi_ext_test.rb b/activesupport/test/core_ext/cgi_ext_test.rb deleted file mode 100644 index c80362e382..0000000000 --- a/activesupport/test/core_ext/cgi_ext_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'abstract_unit' -require 'active_support/core_ext/cgi' - -class EscapeSkippingSlashesTest < Test::Unit::TestCase - def test_array - assert_equal 'hello/world', CGI.escape_skipping_slashes(%w(hello world)) - assert_equal 'hello+world/how/are/you', CGI.escape_skipping_slashes(['hello world', 'how', 'are', 'you']) - end - - def test_typical - assert_equal 'hi', CGI.escape_skipping_slashes('hi') - assert_equal 'hi/world', CGI.escape_skipping_slashes('hi/world') - assert_equal 'hi/world+you+funky+thing', CGI.escape_skipping_slashes('hi/world you funky thing') - end -end diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index 6cbd1f21c0..d05e031f56 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -1,5 +1,4 @@ require "cgi" -require "active_support/core_ext/cgi" module Rails module Info -- cgit v1.2.3 From c20838596bcb40bf1590f27f6ba735d0a5f4fe8f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 10 Nov 2010 16:56:01 -0200 Subject: Remove unused method --- .../core_ext/object/instance_variables.rb | 31 ---------------------- .../test/core_ext/object_and_class_ext_test.rb | 31 ---------------------- 2 files changed, 62 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb index 77a3cfc21d..eda9694614 100644 --- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb +++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb @@ -30,35 +30,4 @@ class Object else alias_method :instance_variable_names, :instance_variables end - - # Copies the instance variables of +object+ into +self+. - # - # Instance variable names in the +exclude+ array are ignored. If +object+ - # responds to protected_instance_variables the ones returned are - # also ignored. For example, Rails controllers implement that method. - # - # In both cases strings and symbols are understood, and they have to include - # the at sign. - # - # class C - # def initialize(x, y, z) - # @x, @y, @z = x, y, z - # end - # - # def protected_instance_variables - # %w(@z) - # end - # end - # - # a = C.new(0, 1, 2) - # b = C.new(3, 4, 5) - # - # a.copy_instance_variables_from(b, [:@y]) - # # a is now: @x = 3, @y = 1, @z = 2 - def copy_instance_variables_from(object, exclude = []) #:nodoc: - exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables - - vars = object.instance_variables.map(&:to_s) - exclude.map(&:to_s) - vars.each { |name| instance_variable_set(name, object.instance_variable_get(name)) } - end end diff --git a/activesupport/test/core_ext/object_and_class_ext_test.rb b/activesupport/test/core_ext/object_and_class_ext_test.rb index 3ccf18f473..64f339ed90 100644 --- a/activesupport/test/core_ext/object_and_class_ext_test.rb +++ b/activesupport/test/core_ext/object_and_class_ext_test.rb @@ -82,37 +82,6 @@ class ObjectInstanceVariableTest < Test::Unit::TestCase assert_equal %w(@bar @baz), @source.instance_variable_names.sort end - def test_copy_instance_variables_from_without_explicit_excludes - assert_equal [], @dest.instance_variables - @dest.copy_instance_variables_from(@source) - - assert_equal %w(@bar @baz), @dest.instance_variables.sort.map(&:to_s) - %w(@bar @baz).each do |name| - assert_equal @source.instance_variable_get(name).object_id, - @dest.instance_variable_get(name).object_id - end - end - - def test_copy_instance_variables_from_with_explicit_excludes - @dest.copy_instance_variables_from(@source, ['@baz']) - assert !@dest.instance_variable_defined?('@baz') - assert_equal 'bar', @dest.instance_variable_get('@bar') - end - - def test_copy_instance_variables_automatically_excludes_protected_instance_variables - @source.instance_variable_set(:@quux, 'quux') - class << @source - def protected_instance_variables - ['@bar', :@quux] - end - end - - @dest.copy_instance_variables_from(@source) - assert !@dest.instance_variable_defined?('@bar') - assert !@dest.instance_variable_defined?('@quux') - assert_equal 'baz', @dest.instance_variable_get('@baz') - end - def test_instance_values object = Object.new object.instance_variable_set :@a, 1 -- cgit v1.2.3 From 7a2be37592a13aaf557619336a54da9092950b18 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 10 Nov 2010 19:12:10 -0200 Subject: Remove copy_instance_variables_from from guides --- .../source/active_support_core_extensions.textile | 33 ---------------------- .../source/api_documentation_guidelines.textile | 12 -------- 2 files changed, 45 deletions(-) diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 9b1d264d2c..8c11b2a11a 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -395,39 +395,6 @@ C.new(0, 1).instance_values # => {"x" => 0, "y" => 1} NOTE: Defined in +active_support/core_ext/object/instance_variables.rb+. -h5. +copy_instance_variables_from(object, exclude = [])+ - -Copies the instance variables of +object+ into +self+. - -Instance variable names in the +exclude+ array are ignored. If +object+ -responds to +protected_instance_variables+ the ones returned are -also ignored. For example, Rails controllers implement that method. - -In both arrays strings and symbols are understood, and they have to include -the at sign. - - -class C - def initialize(x, y, z) - @x, @y, @z = x, y, z - end - - def protected_instance_variables - %w(@z) - end -end - -a = C.new(0, 1, 2) -b = C.new(3, 4, 5) - -a.copy_instance_variables_from(b, [:@y]) -# a is now: @x = 3, @y = 1, @z = 2 - - -In the example +object+ and +self+ are of the same type, but they don't need to. - -NOTE: Defined in +active_support/core_ext/object/instance_variables.rb+. - h4. Silencing Warnings, Streams, and Exceptions The methods +silence_warnings+ and +enable_warnings+ change the value of +$VERBOSE+ accordingly for the duration of their block, and reset it afterwards: diff --git a/railties/guides/source/api_documentation_guidelines.textile b/railties/guides/source/api_documentation_guidelines.textile index 900b3fb5d5..523fbd8a77 100644 --- a/railties/guides/source/api_documentation_guidelines.textile +++ b/railties/guides/source/api_documentation_guidelines.textile @@ -115,18 +115,6 @@ Use fixed-width fonts for: * method parameters * file names - -# Copies the instance variables of +object+ into +self+. -# -# Instance variable names in the +exclude+ array are ignored. If +object+ -# responds to protected_instance_variables the ones returned are -# also ignored. For example, Rails controllers implement that method. -# ... -def copy_instance_variables_from(object, exclude = []) - ... -end - - WARNING: Using a pair of ++...++ for fixed-width font only works with *words*; that is: anything matching \A\w+\z. For anything else use +<tt>...</tt>+, notably symbols, setters, inline snippets, etc: h4. Regular Font -- cgit v1.2.3 From c577e90f61b060164589e7112838e461c42bfe29 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 10 Nov 2010 23:46:00 +0100 Subject: restores the example for fixed-width font in API guidelines --- railties/guides/source/api_documentation_guidelines.textile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/railties/guides/source/api_documentation_guidelines.textile b/railties/guides/source/api_documentation_guidelines.textile index 523fbd8a77..e3ccd6396c 100644 --- a/railties/guides/source/api_documentation_guidelines.textile +++ b/railties/guides/source/api_documentation_guidelines.textile @@ -115,6 +115,16 @@ Use fixed-width fonts for: * method parameters * file names + +class Array + # Calls to_param on all its elements and joins the result with + # slashes. This is used by url_for in Action Pack. + def to_param + collect { |e| e.to_param }.join '/' + end +end + + WARNING: Using a pair of ++...++ for fixed-width font only works with *words*; that is: anything matching \A\w+\z. For anything else use +<tt>...</tt>+, notably symbols, setters, inline snippets, etc: h4. Regular Font -- cgit v1.2.3 From 5dc7f34dca3a5b0bd65dff157ae547347e86670e Mon Sep 17 00:00:00 2001 From: Alvaro Bautista Date: Sat, 11 Sep 2010 21:12:10 +0200 Subject: Fix ActiveSupport::TimeWithZone#localtime method with DateTime [#5344 state:committed] Signed-off-by: Santiago Pastorino --- activesupport/lib/active_support/time_with_zone.rb | 2 +- activesupport/test/core_ext/time_with_zone_test.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 93f5d5a0cc..d993ba3c2a 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -73,7 +73,7 @@ module ActiveSupport # Returns a Time.local() instance of the simultaneous time in your system's ENV['TZ'] zone def localtime - utc.getlocal + utc.is_a?(DateTime) ? utc.to_time.getlocal : utc.getlocal end alias_method :getlocal, :localtime diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 0bb2c4a39e..5579c27215 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -36,6 +36,10 @@ class TimeWithZoneTest < Test::Unit::TestCase assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone['Eastern Time (US & Canada)']).object_id end + def test_localtime + assert_equal @twz.localtime, @twz.utc.getlocal + end + def test_utc? assert_equal false, @twz.utc? assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']).utc? @@ -763,6 +767,13 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase end end + def test_localtime + Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + assert_equal @dt.in_time_zone.localtime, @dt.in_time_zone.utc.to_time.getlocal + ensure + Time.zone_default = nil + end + def test_use_zone Time.zone = 'Alaska' Time.use_zone 'Hawaii' do -- cgit v1.2.3 From 2651a87a33981953e2f7966c69dc87e370a7ff11 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 11 Nov 2010 01:33:27 -0200 Subject: Duck typing here --- activesupport/lib/active_support/time_with_zone.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index d993ba3c2a..6a7da8266c 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -73,7 +73,7 @@ module ActiveSupport # Returns a Time.local() instance of the simultaneous time in your system's ENV['TZ'] zone def localtime - utc.is_a?(DateTime) ? utc.to_time.getlocal : utc.getlocal + utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal end alias_method :getlocal, :localtime -- cgit v1.2.3 From 9c9f416d398c47dd2297fa5cc4025e0800d32212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 11 Nov 2010 14:17:14 +0100 Subject: Allow AR Session Store to be renewed --- .../test/activerecord/active_record_store_test.rb | 20 ++++++++++++++++++++ activerecord/lib/active_record/session_store.rb | 1 + 2 files changed, 21 insertions(+) diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index f5811a1530..7c595d1b89 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -27,6 +27,12 @@ class ActiveRecordStoreTest < ActionDispatch::IntegrationTest head :ok end + def renew + env["rack.session.options"][:renew] = true + session[:foo] = "baz" + head :ok + end + def rescue_action(e) raise end end @@ -64,6 +70,20 @@ class ActiveRecordStoreTest < ActionDispatch::IntegrationTest end end end + + define_method("test_renewing_with_#{class_name}_store") do + with_store class_name do + with_test_route_set do + get '/set_session_value' + assert_response :success + assert cookies['_session_id'] + + get '/renew' + assert_response :success + assert_not_equal [], headers['Set-Cookie'] + end + end + end end def test_getting_nil_session_value diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb index a64c5f80c9..ba99800fb2 100644 --- a/activerecord/lib/active_record/session_store.rb +++ b/activerecord/lib/active_record/session_store.rb @@ -321,6 +321,7 @@ module ActiveRecord if sid = current_session_id(env) Base.silence do get_session_model(env, sid).destroy + env[SESSION_RECORD_KEY] = nil end end -- cgit v1.2.3 From 920660b19c5419c6df1c234a84e7fec71b169544 Mon Sep 17 00:00:00 2001 From: Aditya Sanghi Date: Fri, 15 Oct 2010 22:43:01 +0530 Subject: patching to ensure separator is printed with order [#5816 state:resolved] Signed-off-by: Santiago Pastorino --- actionpack/lib/action_view/helpers/date_helper.rb | 2 ++ actionpack/test/template/date_helper_test.rb | 41 +++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index c1214bc44e..875ec9b77b 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -882,6 +882,8 @@ module ActionView # Returns the separator for a given datetime component def separator(type) case type + when :year + @options[:discard_year] ? "" : @options[:date_separator] when :month @options[:discard_month] ? "" : @options[:date_separator] when :day diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index 0cf7885772..55c384e68f 100644 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -1584,6 +1584,47 @@ class DateHelperTest < ActionView::TestCase assert_dom_equal expected, date_select("post", "written_on", { :date_separator => " / " }) end + def test_date_select_with_separator_and_order + @post = Post.new + @post.written_on = Date.new(2004, 6, 15) + + expected = %{\n" + + expected << " / " + + expected << %{\n" + + expected << " / " + + expected << %{\n" + + assert_dom_equal expected, date_select("post", "written_on", { :order => [:day, :month, :year], :date_separator => " / " }) + end + + def test_date_select_with_separator_and_order_and_year_discarded + @post = Post.new + @post.written_on = Date.new(2004, 6, 15) + + expected = %{\n" + + expected << " / " + + expected << %{\n" + expected << %{\n} + + assert_dom_equal expected, date_select("post", "written_on", { :order => [:day, :month, :year], :discard_year => true, :date_separator => " / " }) + end + def test_date_select_with_default_prompt @post = Post.new @post.written_on = Date.new(2004, 6, 15) -- cgit v1.2.3 From 50c7aab996baafdfee4b1e4b2ca4673ee76bb19a Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 11 Nov 2010 01:30:40 -0200 Subject: Fix issue with rendering partials and then yielding inside a render layout call The given block was never being executed when another render :partial call existed before the yield call, due to the block being overriden. This commit also adds some more tests to render with :layout option. --- .../test/fixtures/layouts/_partial_and_yield.erb | 2 ++ actionpack/test/fixtures/layouts/_yield_only.erb | 1 + .../test/fixtures/layouts/_yield_with_params.erb | 1 + .../layouts/yield_with_render_partial_inside.erb | 2 ++ actionpack/test/template/render_test.rb | 20 ++++++++++++++++++++ 5 files changed, 26 insertions(+) create mode 100644 actionpack/test/fixtures/layouts/_partial_and_yield.erb create mode 100644 actionpack/test/fixtures/layouts/_yield_only.erb create mode 100644 actionpack/test/fixtures/layouts/_yield_with_params.erb create mode 100644 actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb diff --git a/actionpack/test/fixtures/layouts/_partial_and_yield.erb b/actionpack/test/fixtures/layouts/_partial_and_yield.erb new file mode 100644 index 0000000000..74cc428ffa --- /dev/null +++ b/actionpack/test/fixtures/layouts/_partial_and_yield.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'test/partial' %> +<%= yield %> diff --git a/actionpack/test/fixtures/layouts/_yield_only.erb b/actionpack/test/fixtures/layouts/_yield_only.erb new file mode 100644 index 0000000000..37f0bddbd7 --- /dev/null +++ b/actionpack/test/fixtures/layouts/_yield_only.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/actionpack/test/fixtures/layouts/_yield_with_params.erb b/actionpack/test/fixtures/layouts/_yield_with_params.erb new file mode 100644 index 0000000000..68e6557fb8 --- /dev/null +++ b/actionpack/test/fixtures/layouts/_yield_with_params.erb @@ -0,0 +1 @@ +<%= yield 'Yield!' %> diff --git a/actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb b/actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb new file mode 100644 index 0000000000..74cc428ffa --- /dev/null +++ b/actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'test/partial' %> +<%= yield %> diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 17bb610b6a..7736b936a1 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -247,6 +247,26 @@ module RenderTestCases @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield_with_render_inline_inside") end + def test_render_with_layout_which_renders_another_partial + assert_equal %(partial html\nHello world!\n), + @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield_with_render_partial_inside") + end + + def test_render_layout_with_block_and_yield + assert_equal %(Content from block!\n), + @view.render(:layout => "layouts/yield_only") { "Content from block!" } + end + + def test_render_layout_with_block_and_yield_with_params + assert_equal %(Yield! Content from block!\n), + @view.render(:layout => "layouts/yield_with_params") { |param| "#{param} Content from block!" } + end + + def test_render_layout_with_block_which_renders_another_partial_and_yields + assert_equal %(partial html\nContent from block!\n), + @view.render(:layout => "layouts/partial_and_yield") { "Content from block!" } + end + def test_render_with_nested_layout assert_equal %(title\n\n
column
\n
content
\n), @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") -- cgit v1.2.3 From 7846fb79e1296986c41250bfea2e115e7683fa61 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 11 Nov 2010 11:08:17 -0200 Subject: Fix render partial with layout and no block When using a render :partial with :layout call, without giving a block, if the given :partial had another render :partial call, the layout was not being rendered. This commit fixes this context by storing variables before rendering the partial, so they are not overrided in any successive call to render partials down the path. All ActionPack tests are ok. --- actionpack/test/fixtures/test/_partial_with_partial.erb | 2 ++ actionpack/test/template/render_test.rb | 10 ++++++++++ 2 files changed, 12 insertions(+) create mode 100644 actionpack/test/fixtures/test/_partial_with_partial.erb diff --git a/actionpack/test/fixtures/test/_partial_with_partial.erb b/actionpack/test/fixtures/test/_partial_with_partial.erb new file mode 100644 index 0000000000..ee0d5037b6 --- /dev/null +++ b/actionpack/test/fixtures/test/_partial_with_partial.erb @@ -0,0 +1,2 @@ +<%= render 'test/partial' %> +partial with partial diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 7736b936a1..08d50257d4 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -267,6 +267,16 @@ module RenderTestCases @view.render(:layout => "layouts/partial_and_yield") { "Content from block!" } end + def test_render_partial_and_layout_without_block_with_locals + assert_equal %(Before (Foo!)\npartial html\nAfter), + @view.render(:partial => 'test/partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_partial_and_layout_without_block_with_locals_and_rendering_another_partial + assert_equal %(Before (Foo!)\npartial html\npartial with partial\n\nAfter), + @view.render(:partial => 'test/partial_with_partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + def test_render_with_nested_layout assert_equal %(title\n\n
column
\n
content
\n), @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") -- cgit v1.2.3 From 2bb1c202b48c4f1c8d81927fb3e5fc00806231f9 Mon Sep 17 00:00:00 2001 From: Marcelo Giorgi Date: Sun, 3 Oct 2010 12:16:52 -0200 Subject: Make after_filter halt when before_filter renders or redirects [#5648 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/abstract_controller/callbacks.rb | 2 + actionpack/test/controller/filters_test.rb | 81 ++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 7b0d80614d..094e62b9c7 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -83,6 +83,7 @@ module AbstractController # for details on the allowed parameters. def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk) _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options} + options[:if]=(Array.wrap(options[:if]) << "!halted") if #{filter == :after} set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before_filter, name, options) end # end end # end @@ -91,6 +92,7 @@ module AbstractController # for details on the allowed parameters. def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk) _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| + options[:if]=(Array.wrap(options[:if]) << "!halted") if #{filter == :after} set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true)) end # end end # end diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 3a8a37d967..68febf425d 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -78,7 +78,8 @@ class FilterTest < ActionController::TestCase end class RenderingController < ActionController::Base - before_filter :render_something_else + before_filter :before_filter_rendering + after_filter :unreached_after_filter def show @ran_action = true @@ -86,9 +87,59 @@ class FilterTest < ActionController::TestCase end private - def render_something_else + def before_filter_rendering + @ran_filter ||= [] + @ran_filter << "before_filter_rendering" render :inline => "something else" end + + def unreached_after_filter + @ran_filter << "unreached_after_filter_after_render" + end + end + + class RenderingForPrependAfterFilterController < RenderingController + prepend_after_filter :unreached_prepend_after_filter + + private + def unreached_prepend_after_filter + @ran_filter << "unreached_preprend_after_filter_after_render" + end + end + + class BeforeFilterRedirectionController < ActionController::Base + before_filter :before_filter_redirects + after_filter :unreached_after_filter + + def show + @ran_action = true + render :inline => "ran show action" + end + + def target_of_redirection + @ran_target_of_redirection = true + render :inline => "ran target_of_redirection action" + end + + private + def before_filter_redirects + @ran_filter ||= [] + @ran_filter << "before_filter_redirects" + redirect_to(:action => 'target_of_redirection') + end + + def unreached_after_filter + @ran_filter << "unreached_after_filter_after_redirection" + end + end + + class BeforeFilterRedirectionForPrependAfterFilterController < BeforeFilterRedirectionController + prepend_after_filter :unreached_prepend_after_filter_after_redirection + + private + def unreached_prepend_after_filter_after_redirection + @ran_filter << "unreached_prepend_after_filter_after_redirection" + end end class ConditionalFilterController < ActionController::Base @@ -625,6 +676,32 @@ class FilterTest < ActionController::TestCase assert !assigns["ran_action"] end + def test_before_filter_rendering_breaks_filtering_chain_for_after_filter + response = test_process(RenderingController) + assert_equal %w( before_filter_rendering ), assigns["ran_filter"] + assert !assigns["ran_action"] + end + + def test_before_filter_redirects_breaks_filtering_chain_for_after_filter + response = test_process(BeforeFilterRedirectionController) + assert_response :redirect + assert_equal "http://test.host/filter_test/before_filter_redirection/target_of_redirection", redirect_to_url + assert_equal %w( before_filter_redirects ), assigns["ran_filter"] + end + + def test_before_filter_rendering_breaks_filtering_chain_for_preprend_after_filter + response = test_process(RenderingForPrependAfterFilterController) + assert_equal %w( before_filter_rendering ), assigns["ran_filter"] + assert !assigns["ran_action"] + end + + def test_before_filter_redirects_breaks_filtering_chain_for_preprend_after_filter + response = test_process(BeforeFilterRedirectionForPrependAfterFilterController) + assert_response :redirect + assert_equal "http://test.host/filter_test/before_filter_redirection_for_prepend_after_filter/target_of_redirection", redirect_to_url + assert_equal %w( before_filter_redirects ), assigns["ran_filter"] + end + def test_filters_with_mixed_specialization_run_in_order assert_nothing_raised do response = test_process(MixedSpecializationController, 'bar') -- cgit v1.2.3 From a8974028634a1ff5ecce46c1a79d305f58ba4338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 11 Nov 2010 17:07:06 +0100 Subject: Remove inline comment. --- actionpack/lib/abstract_controller/callbacks.rb | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 094e62b9c7..f169ab7c3a 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -81,29 +81,29 @@ module AbstractController class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 # Append a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options} - options[:if]=(Array.wrap(options[:if]) << "!halted") if #{filter == :after} - set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before_filter, name, options) - end # end - end # end + def #{filter}_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| + options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after} + set_callback(:process_action, :#{filter}, name, options) + end + end # Prepend a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| - options[:if]=(Array.wrap(options[:if]) << "!halted") if #{filter == :after} - set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true)) - end # end - end # end + def prepend_#{filter}_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| + options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after} + set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) + end + end # Skip a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def skip_#{filter}_filter(*names, &blk) # def skip_before_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| - skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options) - end # end - end # end + def skip_#{filter}_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| + skip_callback(:process_action, :#{filter}, name, options) + end + end # *_filter is the same as append_*_filter alias_method :append_#{filter}_filter, :#{filter}_filter -- cgit v1.2.3 From fbaf3a23d909bca79bae3ebb77249483fcab5383 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Thu, 11 Nov 2010 10:02:14 -0500 Subject: fields_for should treat ActiveRecord::Relation as an array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#5795 state:resolved] Signed-off-by: José Valim --- actionpack/lib/action_view/helpers/form_helper.rb | 4 ++-- actionpack/test/lib/controller/fake_models.rb | 10 ++++++++++ actionpack/test/template/form_helper_test.rb | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 80a872068d..0470b051c6 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1277,11 +1277,11 @@ module ActionView if association.respond_to?(:persisted?) association = [association] if @object.send(association_name).is_a?(Array) - elsif !association.is_a?(Array) + elsif !association.respond_to?(:to_ary) association = @object.send(association_name) end - if association.is_a?(Array) + if association.respond_to?(:to_ary) explicit_child_index = options[:child_index] output = ActiveSupport::SafeBuffer.new association.each do |child| diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index dba632e6df..ae0c38184d 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -184,3 +184,13 @@ module Blog end end end + +class ArelLike + def to_ary + true + end + def each + a = Array.new(2) { |id| Comment.new(id + 1) } + a.each { |i| yield i } + end +end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index acb6e7aa64..2c60096475 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1230,6 +1230,27 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_nested_fields_for_arel_like + @post.comments = ArelLike.new + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:comments, @post.comments) { |cf| + concat cf.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', :method => 'put') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + def test_nested_fields_for_with_existing_records_on_a_supplied_nested_attributes_collection_different_from_record_one comments = Array.new(2) { |id| Comment.new(id + 1) } @post.comments = [] -- cgit v1.2.3 From 154e5d735efcc840c3be52a19b1f8a89eeb2e9e9 Mon Sep 17 00:00:00 2001 From: Jeff Kreeftmeijer Date: Thu, 14 Oct 2010 21:23:19 +0200 Subject: The model generator shouldn't throw warnings when using mass nouns [#5363 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/generators/resource_helpers.rb | 2 +- railties/test/generators/resource_generator_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 829f4b200a..8400171aa1 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -17,7 +17,7 @@ module Rails def initialize(*args) #:nodoc: super - if name == name.pluralize && !options[:force_plural] + if name == name.pluralize && name.singularize != name.pluralize && !options[:force_plural] unless ResourceHelpers.skip_warn say "Plural version of the model detected, using singularized version. Override with --force-plural." ResourceHelpers.skip_warn = true diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 55d5bd6f83..71b3619351 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -73,6 +73,11 @@ class ResourceGeneratorTest < Rails::Generators::TestCase assert_no_match /Plural version of the model detected/, content end + def test_mass_nouns_do_not_throw_warnings + content = run_generator ["sheep".freeze] + assert_no_match /Plural version of the model detected/, content + end + def test_route_is_removed_on_revoke run_generator run_generator ["account"], :behavior => :revoke -- cgit v1.2.3 From 793967cd404c839c1af8b3ef847dc1725a1fb7c6 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 3 Nov 2010 10:52:50 -0400 Subject: provide better error message if path is uri [#5914 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/helpers/asset_tag_helper.rb | 8 +++++--- actionpack/test/template/asset_tag_helper_test.rb | 11 +++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index a728fde748..db5f5f301a 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -878,7 +878,7 @@ module ActionView end def join_asset_file_contents(paths) - paths.collect { |path| File.read(asset_file_path!(path)) }.join("\n\n") + paths.collect { |path| File.read(asset_file_path!(path, true)) }.join("\n\n") end def write_asset_file_contents(joined_asset_path, asset_paths) @@ -896,8 +896,10 @@ module ActionView File.join(config.assets_dir, path.split('?').first) end - def asset_file_path!(path) - unless is_uri?(path) + def asset_file_path!(path, error_if_file_is_uri = false) + if is_uri?(path) + raise(Errno::ENOENT, "Asset file #{path} is uri and cannot be merged into single file") if error_if_file_is_uri + else absolute_path = asset_file_path(path) raise(Errno::ENOENT, "Asset file not found at '#{absolute_path}'" ) unless File.exist?(absolute_path) return absolute_path diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 3abcdfbc1e..caf1c694c8 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -727,6 +727,17 @@ class AssetTagHelperTest < ActionView::TestCase assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) end + def test_caching_javascript_include_tag_when_caching_on_and_javascript_file_is_uri + ENV["RAILS_ASSET_ID"] = "" + config.perform_caching = true + + assert_raise(Errno::ENOENT) { + javascript_include_tag('bank', 'robber', 'https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.js', :cache => true) + } + + assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) + end + def test_caching_javascript_include_tag_when_caching_off_and_missing_javascript_file ENV["RAILS_ASSET_ID"] = "" config.perform_caching = false -- cgit v1.2.3 From 8a6ac4fc26bacbd2a6c978cace156e300b77508e Mon Sep 17 00:00:00 2001 From: zhengjia Date: Tue, 26 Oct 2010 22:13:12 -0500 Subject: Remove unused Configurable in Rails::Engine and Rails::Application. Remove unnecessary railties load path in cli [#5871 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/application.rb | 1 - railties/lib/rails/cli.rb | 3 --- railties/lib/rails/engine.rb | 1 - 3 files changed, 5 deletions(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index d84373cddf..182068071d 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -35,7 +35,6 @@ module Rails # class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' - autoload :Configurable, 'rails/application/configurable' autoload :Configuration, 'rails/application/configuration' autoload :Finisher, 'rails/application/finisher' autoload :Railties, 'rails/application/railties' diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb index 1260772605..a4b86974c2 100644 --- a/railties/lib/rails/cli.rb +++ b/railties/lib/rails/cli.rb @@ -5,9 +5,6 @@ require 'rails/script_rails_loader' # the rest of this script is not run. Rails::ScriptRailsLoader.exec_script_rails! -railties_path = File.expand_path('../../lib', __FILE__) -$:.unshift(railties_path) if File.directory?(railties_path) && !$:.include?(railties_path) - require 'rails/ruby_version_check' Signal.trap("INT") { puts; exit } diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 72bfe207d7..33dcdde8d0 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -324,7 +324,6 @@ module Rails # MyEngine::Engine.load_seed # class Engine < Railtie - autoload :Configurable, "rails/engine/configurable" autoload :Configuration, "rails/engine/configuration" class << self -- cgit v1.2.3 From 37d3266f35e1947f43046fb8296c560145f2b53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 11 Nov 2010 17:30:24 +0100 Subject: Add missing autoload. --- railties/lib/rails/engine.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 33dcdde8d0..466a31c2a0 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -325,6 +325,7 @@ module Rails # class Engine < Railtie autoload :Configuration, "rails/engine/configuration" + autoload :Railties, "rails/engine/railties" class << self attr_accessor :called_from, :isolated -- cgit v1.2.3 From bafa1533f414a3d3c02528b774e5cf28e85774b5 Mon Sep 17 00:00:00 2001 From: Rob Zolkos Date: Wed, 20 Oct 2010 00:15:35 +1100 Subject: skip testing framework if app created with --skip-test-unit [#5796 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/rails/generators/rails/app/templates/config/application.rb | 4 ++++ railties/test/generators/app_generator_test.rb | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 00a23a7b89..6e515756fe 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -48,6 +48,10 @@ module <%= app_const_base %> # config.action_view.javascript_expansions[:defaults] = %w(jquery rails) <% end -%> +<% if options[:skip_test_unit] -%> + config.generators.test_framework = false +<% end -%> + # Configure the default encoding used in templates for Ruby 1.9. config.encoding = "utf-8" diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index c7339cb8d2..f4d2027874 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -188,6 +188,13 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "test" end + def test_test_unit_is_removed_from_frameworks_if_skip_test_unit_is_given + run_generator [destination_root, "--skip-test-unit"] + assert_file "config/application.rb" do |file| + assert_match /config.generators.test_framework = false/, file + end + end + def test_test_unit_is_skipped_if_required run_generator [destination_root, "--skip-test-unit"] assert_no_file "test" -- cgit v1.2.3 From ceef719924b566a519465de96bd29344ee4d2fed Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 11 Nov 2010 15:03:30 -0200 Subject: Bump Arel up to 2.0.2 --- activerecord/activerecord.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index b8a980b1fb..b1df24844a 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -23,6 +23,6 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) - s.add_dependency('arel', '~> 2.0.0') + s.add_dependency('arel', '~> 2.0.2') s.add_dependency('tzinfo', '~> 0.3.23') end -- cgit v1.2.3 From 894fd288596b005148c3882e6431f6453d198101 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 11 Nov 2010 15:23:37 -0200 Subject: Fixed bug in active_record/nested_attributes where an empty string id caused an ActiveRecord::RecordNotFound error. Found by [Ben Tillman] [#5638 state:committed] Signed-off-by: Santiago Pastorino --- activerecord/lib/active_record/nested_attributes.rb | 2 +- activerecord/test/cases/nested_attributes_test.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index aca91c907d..bbce6df98f 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -323,7 +323,7 @@ module ActiveRecord (options[:update_only] || record.id.to_s == attributes['id'].to_s) assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) - elsif attributes['id'] + elsif not attributes['id'].blank? raise_nested_attributes_record_not_found(association_name, attributes['id']) elsif !reject_new_record?(association_name, attributes) diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 765f59e0ac..92af53d56f 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -139,6 +139,14 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase assert_equal 'gardening', interest.reload.topic end + def test_reject_if_with_blank_nested_attributes_id + # When using a select list to choose an existing 'ship' id, with :include_blank => true + Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:id].blank? } + + pirate = Pirate.new(:catchphrase => "Stop wastin' me time") + pirate.ship_attributes = { :id => "" } + assert_nothing_raised(ActiveRecord::RecordNotFound) { pirate.save! } + end end class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase -- cgit v1.2.3 From 296e5c38f1b501d39c247f5b7daccedded4e497b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 11 Nov 2010 15:24:49 -0200 Subject: Use ! instead of not --- activerecord/lib/active_record/nested_attributes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index bbce6df98f..fb48459b6f 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -323,7 +323,7 @@ module ActiveRecord (options[:update_only] || record.id.to_s == attributes['id'].to_s) assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) - elsif not attributes['id'].blank? + elsif !attributes['id'].blank? raise_nested_attributes_record_not_found(association_name, attributes['id']) elsif !reject_new_record?(association_name, attributes) -- cgit v1.2.3 From de2933e1a062f0752512eb0ec60f7217f4890f8c Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Fri, 12 Nov 2010 01:37:12 +0800 Subject: STI type is now updated when calling AR::Base.becomes on subclasses [#5953 state:resolved] --- activerecord/lib/active_record/persistence.rb | 1 + activerecord/test/cases/persistence_test.rb | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 00d49dd0f6..594a2214bb 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -96,6 +96,7 @@ module ActiveRecord became.instance_variable_set("@attributes_cache", @attributes_cache) became.instance_variable_set("@persisted", persisted?) became.instance_variable_set("@destroyed", destroyed?) + became.type = klass.name unless self.class.descends_from_active_record? became end diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index ffe6fb95b8..07262f56be 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -241,6 +241,15 @@ class PersistencesTest < ActiveRecord::TestCase assert_nothing_raised { minimalistic.save } end + def test_update_sti_type + assert_instance_of Reply, topics(:second) + + topic = topics(:second).becomes(Topic) + assert_instance_of Topic, topic + topic.save! + assert_instance_of Topic, Topic.find(topic.id) + end + def test_delete topic = Topic.find(1) assert_equal topic, topic.delete, 'topic.delete did not return self' -- cgit v1.2.3 From c63600576a7ca63d1a7243308ca8cc7f0e3cde75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 11 Nov 2010 20:07:47 +0100 Subject: Remove whitespaces and add missing test. --- railties/test/generators/app_generator_test.rb | 17 ++++++++++++----- railties/test/generators/plugin_new_generator_test.rb | 1 - 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 6b2026ad0c..7faa674a81 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -83,11 +83,11 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "myapp_moved/config/environment.rb", /Myapp::Application\.initialize!/ assert_file "myapp_moved/config/initializers/session_store.rb", /_myapp_session/ end - + def test_rails_update_generates_correct_session_key app_root = File.join(destination_root, 'myapp') run_generator [app_root] - + Rails.application.config.root = app_root Rails.application.class.stubs(:name).returns("Myapp") Rails.application.stubs(:is_a?).returns(Rails::Application) @@ -137,7 +137,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "public/javascripts/rails.js" assert_file "test" end - + def test_javascript_is_skipped_if_required run_generator [destination_root, "--skip-javascript"] assert_file "config/application.rb", /^\s+config\.action_view\.javascript_expansions\[:defaults\]\s+=\s+%w\(\)/ @@ -145,7 +145,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_file "public/javascripts/prototype.js" assert_no_file "public/javascripts/rails.js" end - + def test_config_prototype_javascript_library run_generator [destination_root, "-j", "prototype"] assert_file "config/application.rb", /#\s+config\.action_view\.javascript_expansions\[:defaults\]\s+=\s+%w\(jquery rails\)/ @@ -153,7 +153,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "public/javascripts/prototype.js" assert_file "public/javascripts/rails.js", /prototype/ end - + def test_config_jquery_javascript_library run_generator [destination_root, "-j", "jquery"] assert_file "config/application.rb", /^\s+config\.action_view\.javascript_expansions\[:defaults\]\s+=\s+%w\(jquery rails\)/ @@ -186,6 +186,13 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file 'lib/test_file.rb', 'heres test data' end + def test_test_unit_is_removed_from_frameworks_if_skip_test_unit_is_given + run_generator [destination_root, "--skip-test-unit"] + assert_file "config/application.rb" do |file| + assert_match /config.generators.test_framework = false/, file + end + end + protected def action(*args, &block) diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 8dc5ca90ba..12cae7cfdf 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -18,7 +18,6 @@ DEFAULT_PLUGIN_FILES = %w( test/dummy ) - class PluginNewGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper destination File.join(Rails.root, "tmp/bukkits") -- cgit v1.2.3 From b734e192a70d63b4420a96a00e4f181d27e30129 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 11 Nov 2010 18:59:54 -0200 Subject: present? is better here --- activerecord/lib/active_record/nested_attributes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index fb48459b6f..0c3392263a 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -323,7 +323,7 @@ module ActiveRecord (options[:update_only] || record.id.to_s == attributes['id'].to_s) assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) - elsif !attributes['id'].blank? + elsif attributes['id'].present? raise_nested_attributes_record_not_found(association_name, attributes['id']) elsif !reject_new_record?(association_name, attributes) -- cgit v1.2.3 From b15d816166c64894bfe33860f4949772c8806f2f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 12 Nov 2010 12:55:46 -0200 Subject: Update to JQuery 1.4.4 Check out http://blog.jquery.com/2010/11/11/jquery-1-4-4-release-notes/ for information on what's new. --- .../app/templates/public/javascripts/jquery.js | 984 ++++++++++++++------- 1 file changed, 640 insertions(+), 344 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js index ad9a79c433..a4f114586c 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/jquery.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v1.4.3 + * jQuery JavaScript Library v1.4.4 * http://jquery.com/ * * Copyright 2010, John Resig @@ -11,7 +11,7 @@ * Copyright 2010, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * - * Date: Thu Oct 14 23:10:06 2010 -0400 + * Date: Thu Nov 11 19:04:53 2010 -0500 */ (function( window, undefined ) { @@ -211,7 +211,7 @@ jQuery.fn = jQuery.prototype = { selector: "", // The current version of jQuery being used - jquery: "1.4.3", + jquery: "1.4.4", // The default length of a jQuery object is 0 length: 0, @@ -330,8 +330,11 @@ jQuery.fn = jQuery.prototype = { jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { - // copy reference to target object - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy, copyIsArray; + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { @@ -433,18 +436,21 @@ jQuery.extend({ // If there are functions bound, to execute if ( readyList ) { // Execute all of them - var fn, i = 0; - while ( (fn = readyList[ i++ ]) ) { - fn.call( document, jQuery ); - } + var fn, + i = 0, + ready = readyList; // Reset the list of functions readyList = null; - } - // Trigger any bound ready events - if ( jQuery.fn.triggerHandler ) { - jQuery( document ).triggerHandler( "ready" ); + while ( (fn = ready[ i++ ]) ) { + fn.call( document, jQuery ); + } + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).unbind( "ready" ); + } } } }, @@ -697,7 +703,8 @@ jQuery.extend({ }, merge: function( first, second ) { - var i = first.length, j = 0; + var i = first.length, + j = 0; if ( typeof second.length === "number" ) { for ( var l = second.length; j < l; j++ ) { @@ -964,6 +971,7 @@ return (window.jQuery = window.$ = jQuery); optSelected: opt.selected, // Will be defined later + deleteExpando: true, optDisabled: false, checkClone: false, scriptEval: false, @@ -994,6 +1002,15 @@ return (window.jQuery = window.$ = jQuery); delete window[ id ]; } + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete script.test; + + } catch(e) { + jQuery.support.deleteExpando = false; + } + root.removeChild( script ); if ( div.attachEvent && div.fireEvent ) { @@ -1087,20 +1104,6 @@ return (window.jQuery = window.$ = jQuery); root = script = div = all = a = null; })(); -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; - - var windowData = {}, @@ -1237,8 +1240,24 @@ jQuery.extend({ jQuery.fn.extend({ data: function( key, value ) { + var data = null; + if ( typeof key === "undefined" ) { - return this.length ? jQuery.data( this[0] ) : null; + if ( this.length ) { + var attr = this[0].attributes, name; + data = jQuery.data( this[0] ); + + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = name.substr( 5 ); + dataAttr( this[0], name, data[ name ] ); + } + } + } + + return data; } else if ( typeof key === "object" ) { return this.each(function() { @@ -1250,31 +1269,12 @@ jQuery.fn.extend({ parts[1] = parts[1] ? "." + parts[1] : ""; if ( value === undefined ) { - var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); // Try to fetch any internally stored data first if ( data === undefined && this.length ) { data = jQuery.data( this[0], key ); - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && this[0].nodeType === 1 ) { - data = this[0].getAttribute( "data-" + key ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - !jQuery.isNaN( data ) ? parseFloat( data ) : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - } else { - data = undefined; - } - } + data = dataAttr( this[0], key, data ); } return data === undefined && parts[1] ? @@ -1283,7 +1283,8 @@ jQuery.fn.extend({ } else { return this.each(function() { - var $this = jQuery( this ), args = [ parts[0], value ]; + var $this = jQuery( this ), + args = [ parts[0], value ]; $this.triggerHandler( "setData" + parts[1] + "!", args ); jQuery.data( this, key, value ); @@ -1299,6 +1300,33 @@ jQuery.fn.extend({ } }); +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + data = elem.getAttribute( "data-" + key ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( data ) : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + @@ -1329,7 +1357,8 @@ jQuery.extend({ dequeue: function( elem, type ) { type = type || "fx"; - var queue = jQuery.queue( elem, type ), fn = queue.shift(); + var queue = jQuery.queue( elem, type ), + fn = queue.shift(); // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { @@ -1405,6 +1434,19 @@ var rclass = /[\n\t]/g, rclickable = /^a(?:rea)?$/i, rradiocheck = /^(?:radio|checkbox)$/i; +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; + jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); @@ -1438,7 +1480,9 @@ jQuery.fn.extend({ elem.className = value; } else { - var className = " " + elem.className + " ", setClass = elem.className; + var className = " " + elem.className + " ", + setClass = elem.className; + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { setClass += " " + classNames[c]; @@ -1486,7 +1530,8 @@ jQuery.fn.extend({ }, toggleClass: function( value, stateVal ) { - var type = typeof value, isBool = typeof stateVal === "boolean"; + var type = typeof value, + isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { return this.each(function(i) { @@ -1498,7 +1543,9 @@ jQuery.fn.extend({ return this.each(function() { if ( type === "string" ) { // toggle individual class names - var className, i = 0, self = jQuery(this), + var className, + i = 0, + self = jQuery( this ), state = stateVal, classNames = value.split( rspaces ); @@ -1667,91 +1714,88 @@ jQuery.extend({ // Try to normalize/fix the name name = notxml && jQuery.props[ name ] || name; - // Only do all the following if this is a node (faster for style) - if ( elem.nodeType === 1 ) { - // These attributes require special treatment - var special = rspecialurl.test( name ); - - // Safari mis-reports the default selected property of an option - // Accessing the parent's selectedIndex property fixes it - if ( name === "selected" && !jQuery.support.optSelected ) { - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } + // These attributes require special treatment + var special = rspecialurl.test( name ); - // If applicable, access the attribute via the DOM 0 way - // 'in' checks fail in Blackberry 4.7 #6931 - if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { - if ( set ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; - if ( value === null ) { - if ( elem.nodeType === 1 ) { - elem.removeAttribute( name ); - } - - } else { - elem[ name ] = value; - } + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; } + } + } - // browsers index elements by id/name on forms, give priority to attributes. - if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { - return elem.getAttributeNode( name ).nodeValue; + // If applicable, access the attribute via the DOM 0 way + // 'in' checks fail in Blackberry 4.7 #6931 + if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); } - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - if ( name === "tabIndex" ) { - var attributeNode = elem.getAttributeNode( "tabIndex" ); + if ( value === null ) { + if ( elem.nodeType === 1 ) { + elem.removeAttribute( name ); + } - return attributeNode && attributeNode.specified ? - attributeNode.value : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; + } else { + elem[ name ] = value; } + } - return elem[ name ]; + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; } - if ( !jQuery.support.style && notxml && name === "style" ) { - if ( set ) { - elem.style.cssText = "" + value; - } + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); - return elem.style.cssText; + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; } + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { if ( set ) { - // convert the value to a string (all browsers do this but IE) see #1070 - elem.setAttribute( name, "" + value ); + elem.style.cssText = "" + value; } - // Ensure that missing attributes return undefined - // Blackberry 4.7 returns "" from getAttribute #6938 - if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { - return undefined; - } + return elem.style.cssText; + } - var attr = !jQuery.support.hrefNormalized && notxml && special ? - // Some attributes require a special call on IE - elem.getAttribute( name, 2 ) : - elem.getAttribute( name ); + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } - // Non-existent attributes return null, we normalize to undefined - return attr === null ? undefined : attr; + // Ensure that missing attributes return undefined + // Blackberry 4.7 returns "" from getAttribute #6938 + if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { + return undefined; } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; } }); @@ -1790,6 +1834,9 @@ jQuery.event = { if ( handler === false ) { handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; } var handleObjIn, handleObj; @@ -2133,8 +2180,10 @@ jQuery.event = { jQuery.event.trigger( event, data, parent, true ); } else if ( !event.isDefaultPrevented() ) { - var target = event.target, old, targetType = type.replace(rnamespaces, ""), - isClick = jQuery.nodeName(target, "a") && targetType === "click", + var old, + target = event.target, + targetType = type.replace( rnamespaces, "" ), + isClick = jQuery.nodeName( target, "a" ) && targetType === "click", special = jQuery.event.special[ targetType ] || {}; if ( (!special._default || special._default.call( elem, event ) === false) && @@ -2166,7 +2215,9 @@ jQuery.event = { }, handle: function( event ) { - var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments ); + var all, handlers, namespaces, namespace_re, events, + namespace_sort = [], + args = jQuery.makeArray( arguments ); event = args[0] = jQuery.event.fix( event || window.event ); event.currentTarget = this; @@ -2245,7 +2296,8 @@ jQuery.event = { // Fix target property, if necessary if ( !event.target ) { - event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; } // check if target is a textnode (safari) @@ -2260,7 +2312,9 @@ jQuery.event = { // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, body = document.body; + var doc = document.documentElement, + body = document.body; + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); } @@ -2466,7 +2520,8 @@ if ( !jQuery.support.submitBubbles ) { setup: function( data, namespaces ) { if ( this.nodeName.toLowerCase() !== "form" ) { jQuery.event.add(this, "click.specialSubmit", function( e ) { - var elem = e.target, type = elem.type; + var elem = e.target, + type = elem.type; if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { e.liveFired = undefined; @@ -2475,7 +2530,8 @@ if ( !jQuery.support.submitBubbles ) { }); jQuery.event.add(this, "keypress.specialSubmit", function( e ) { - var elem = e.target, type = elem.type; + var elem = e.target, + type = elem.type; if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { e.liveFired = undefined; @@ -2716,7 +2772,8 @@ jQuery.fn.extend({ toggle: function( fn ) { // Save reference to arguments for access in closure - var args = arguments, i = 1; + var args = arguments, + i = 1; // link all the functions, so any of them can unbind this click handler while ( i < args.length ) { @@ -2811,8 +2868,9 @@ jQuery.each(["live", "die"], function( i, name ) { }); function liveHandler( event ) { - var stop, maxLevel, elems = [], selectors = [], - related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], events = jQuery.data( this, this.nodeType ? "events" : "__events__" ); if ( typeof events === "function" ) { @@ -2823,7 +2881,7 @@ function liveHandler( event ) { if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) { return; } - + if ( event.namespace ) { namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); } @@ -2887,6 +2945,9 @@ function liveHandler( event ) { if ( ret === false ) { stop = false; } + if ( event.isImmediatePropagationStopped() ) { + break; + } } } @@ -2954,12 +3015,12 @@ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[ // optimization where it does not always call our comparision // function. If that is the case, discard the hasDuplicate value. // Thus far that includes Google Chrome. -[0, 0].sort(function(){ +[0, 0].sort(function() { baseHasDuplicate = false; return 0; }); -var Sizzle = function(selector, context, results, seed) { +var Sizzle = function( selector, context, results, seed ) { results = results || []; context = context || document; @@ -2973,13 +3034,16 @@ var Sizzle = function(selector, context, results, seed) { return results; } - var parts = [], m, set, checkSet, extra, prune = true, contextXML = Sizzle.isXML(context), - soFar = selector, ret, cur, pop, i; + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; // Reset the position of the chunker regexp (start from head) do { - chunker.exec(""); - m = chunker.exec(soFar); + chunker.exec( "" ); + m = chunker.exec( soFar ); if ( m ) { soFar = m[3]; @@ -2994,8 +3058,10 @@ var Sizzle = function(selector, context, results, seed) { } while ( m ); if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context ); + } else { set = Expr.relative[ parts[0] ] ? [ context ] : @@ -3011,23 +3077,31 @@ var Sizzle = function(selector, context, results, seed) { set = posProcess( selector, set ); } } + } else { // Take a shortcut and set the context if the root selector is an ID // (but not if it'll be faster if the inner selector is an ID) if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; } if ( context ) { ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; if ( parts.length > 0 ) { - checkSet = makeArray(set); + checkSet = makeArray( set ); + } else { prune = false; } @@ -3048,6 +3122,7 @@ var Sizzle = function(selector, context, results, seed) { Expr.relative[ cur ]( checkSet, pop, contextXML ); } + } else { checkSet = parts = []; } @@ -3064,12 +3139,14 @@ var Sizzle = function(selector, context, results, seed) { if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { results.push( set[i] ); } } + } else { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { @@ -3077,6 +3154,7 @@ var Sizzle = function(selector, context, results, seed) { } } } + } else { makeArray( checkSet, results ); } @@ -3089,15 +3167,15 @@ var Sizzle = function(selector, context, results, seed) { return results; }; -Sizzle.uniqueSort = function(results){ +Sizzle.uniqueSort = function( results ) { if ( sortOrder ) { hasDuplicate = baseHasDuplicate; - results.sort(sortOrder); + results.sort( sortOrder ); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[i-1] ) { - results.splice(i--, 1); + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); } } } @@ -3106,15 +3184,15 @@ Sizzle.uniqueSort = function(results){ return results; }; -Sizzle.matches = function(expr, set){ - return Sizzle(expr, null, null, set); +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); }; -Sizzle.matchesSelector = function(node, expr){ - return Sizzle(expr, null, null, [node]).length > 0; +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; }; -Sizzle.find = function(expr, context, isXML){ +Sizzle.find = function( expr, context, isXML ) { var set; if ( !expr ) { @@ -3122,15 +3200,17 @@ Sizzle.find = function(expr, context, isXML){ } for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var type = Expr.order[i], match; + var match, + type = Expr.order[i]; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { var left = match[1]; - match.splice(1,1); + match.splice( 1, 1 ); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace(/\\/g, ""); set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; @@ -3140,20 +3220,26 @@ Sizzle.find = function(expr, context, isXML){ } if ( !set ) { - set = context.getElementsByTagName("*"); + set = context.getElementsByTagName( "*" ); } - return {set: set, expr: expr}; + return { set: set, expr: expr }; }; -Sizzle.filter = function(expr, set, inplace, not){ - var old = expr, result = [], curLoop = set, match, anyFound, - isXMLFilter = set && set[0] && Sizzle.isXML(set[0]); +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); while ( expr && set.length ) { for ( var type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - var filter = Expr.filter[ type ], found, item, left = match[1]; + var found, item, + filter = Expr.filter[ type ], + left = match[1]; + anyFound = false; match.splice(1,1); @@ -3171,6 +3257,7 @@ Sizzle.filter = function(expr, set, inplace, not){ if ( !match ) { anyFound = found = true; + } else if ( match === true ) { continue; } @@ -3185,9 +3272,11 @@ Sizzle.filter = function(expr, set, inplace, not){ if ( inplace && found != null ) { if ( pass ) { anyFound = true; + } else { curLoop[i] = false; } + } else if ( pass ) { result.push( item ); anyFound = true; @@ -3216,6 +3305,7 @@ Sizzle.filter = function(expr, set, inplace, not){ if ( expr === old ) { if ( anyFound == null ) { Sizzle.error( expr ); + } else { break; } @@ -3233,6 +3323,7 @@ Sizzle.error = function( msg ) { var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], + match: { ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, @@ -3243,20 +3334,24 @@ var Expr = Sizzle.selectors = { POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ }, + leftMatch: {}, + attrMap: { "class": "className", "for": "htmlFor" }, + attrHandle: { - href: function(elem){ - return elem.getAttribute("href"); + href: function( elem ) { + return elem.getAttribute( "href" ); } }, + relative: { "+": function(checkSet, part){ var isPartStr = typeof part === "string", - isTag = isPartStr && !/\W/.test(part), + isTag = isPartStr && !/\W/.test( part ), isPartStrNotTag = isPartStr && !isTag; if ( isTag ) { @@ -3277,23 +3372,29 @@ var Expr = Sizzle.selectors = { Sizzle.filter( part, checkSet, true ); } }, - ">": function(checkSet, part){ - var isPartStr = typeof part === "string", - elem, i = 0, l = checkSet.length; - if ( isPartStr && !/\W/.test(part) ) { + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !/\W/.test( part ) ) { part = part.toLowerCase(); for ( ; i < l; i++ ) { elem = checkSet[i]; + if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; } } + } else { for ( ; i < l; i++ ) { elem = checkSet[i]; + if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : @@ -3306,8 +3407,11 @@ var Expr = Sizzle.selectors = { } } }, + "": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck, nodeCheck; + var nodeCheck, + doneName = done++, + checkFn = dirCheck; if ( typeof part === "string" && !/\W/.test(part) ) { part = part.toLowerCase(); @@ -3315,22 +3419,26 @@ var Expr = Sizzle.selectors = { checkFn = dirNodeCheck; } - checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); }, - "~": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck, nodeCheck; - if ( typeof part === "string" && !/\W/.test(part) ) { + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } - checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); } }, + find: { - ID: function(match, context, isXML){ + ID: function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); // Check parentNode to catch when Blackberry 4.6 returns @@ -3338,9 +3446,11 @@ var Expr = Sizzle.selectors = { return m && m.parentNode ? [m] : []; } }, - NAME: function(match, context){ + + NAME: function( match, context ) { if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], results = context.getElementsByName(match[1]); + var ret = [], + results = context.getElementsByName( match[1] ); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { @@ -3351,12 +3461,13 @@ var Expr = Sizzle.selectors = { return ret.length === 0 ? null : ret; } }, - TAG: function(match, context){ - return context.getElementsByTagName(match[1]); + + TAG: function( match, context ) { + return context.getElementsByTagName( match[1] ); } }, preFilter: { - CLASS: function(match, curLoop, inplace, result, not, isXML){ + CLASS: function( match, curLoop, inplace, result, not, isXML ) { match = " " + match[1].replace(/\\/g, "") + " "; if ( isXML ) { @@ -3369,6 +3480,7 @@ var Expr = Sizzle.selectors = { if ( !inplace ) { result.push( elem ); } + } else if ( inplace ) { curLoop[i] = false; } @@ -3377,13 +3489,16 @@ var Expr = Sizzle.selectors = { return false; }, - ID: function(match){ + + ID: function( match ) { return match[1].replace(/\\/g, ""); }, - TAG: function(match, curLoop){ + + TAG: function( match, curLoop ) { return match[1].toLowerCase(); }, - CHILD: function(match){ + + CHILD: function( match ) { if ( match[1] === "nth" ) { // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( @@ -3400,7 +3515,8 @@ var Expr = Sizzle.selectors = { return match; }, - ATTR: function(match, curLoop, inplace, result, not, isXML){ + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { var name = match[1].replace(/\\/g, ""); if ( !isXML && Expr.attrMap[name] ) { @@ -3413,122 +3529,156 @@ var Expr = Sizzle.selectors = { return match; }, - PSEUDO: function(match, curLoop, inplace, result, not){ + + PSEUDO: function( match, curLoop, inplace, result, not ) { if ( match[1] === "not" ) { // If we're dealing with a complex expression, or a simple one if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); + } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { result.push.apply( result, ret ); } + return false; } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, - POS: function(match){ + + POS: function( match ) { match.unshift( true ); + return match; } }, + filters: { - enabled: function(elem){ + enabled: function( elem ) { return elem.disabled === false && elem.type !== "hidden"; }, - disabled: function(elem){ + + disabled: function( elem ) { return elem.disabled === true; }, - checked: function(elem){ + + checked: function( elem ) { return elem.checked === true; }, - selected: function(elem){ + + selected: function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly elem.parentNode.selectedIndex; + return elem.selected === true; }, - parent: function(elem){ + + parent: function( elem ) { return !!elem.firstChild; }, - empty: function(elem){ + + empty: function( elem ) { return !elem.firstChild; }, - has: function(elem, i, match){ + + has: function( elem, i, match ) { return !!Sizzle( match[3], elem ).length; }, - header: function(elem){ + + header: function( elem ) { return (/h\d/i).test( elem.nodeName ); }, - text: function(elem){ + + text: function( elem ) { return "text" === elem.type; }, - radio: function(elem){ + radio: function( elem ) { return "radio" === elem.type; }, - checkbox: function(elem){ + + checkbox: function( elem ) { return "checkbox" === elem.type; }, - file: function(elem){ + + file: function( elem ) { return "file" === elem.type; }, - password: function(elem){ + password: function( elem ) { return "password" === elem.type; }, - submit: function(elem){ + + submit: function( elem ) { return "submit" === elem.type; }, - image: function(elem){ + + image: function( elem ) { return "image" === elem.type; }, - reset: function(elem){ + + reset: function( elem ) { return "reset" === elem.type; }, - button: function(elem){ + + button: function( elem ) { return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; }, - input: function(elem){ - return (/input|select|textarea|button/i).test(elem.nodeName); + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); } }, setFilters: { - first: function(elem, i){ + first: function( elem, i ) { return i === 0; }, - last: function(elem, i, match, array){ + + last: function( elem, i, match, array ) { return i === array.length - 1; }, - even: function(elem, i){ + + even: function( elem, i ) { return i % 2 === 0; }, - odd: function(elem, i){ + + odd: function( elem, i ) { return i % 2 === 1; }, - lt: function(elem, i, match){ + + lt: function( elem, i, match ) { return i < match[3] - 0; }, - gt: function(elem, i, match){ + + gt: function( elem, i, match ) { return i > match[3] - 0; }, - nth: function(elem, i, match){ + + nth: function( elem, i, match ) { return match[3] - 0 === i; }, - eq: function(elem, i, match){ + + eq: function( elem, i, match ) { return match[3] - 0 === i; } }, filter: { - PSEUDO: function(elem, match, i, array){ - var name = match[1], filter = Expr.filters[ name ]; + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); + } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { var not = match[3]; @@ -3539,33 +3689,43 @@ var Expr = Sizzle.selectors = { } return true; + } else { Sizzle.error( "Syntax error, unrecognized expression: " + name ); } }, - CHILD: function(elem, match){ - var type = match[1], node = elem; - switch (type) { - case 'only': - case 'first': + + CHILD: function( elem, match ) { + var type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) { return false; } } + if ( type === "first" ) { return true; } + node = elem; - case 'last': + + case "last": while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) { return false; } } + return true; - case 'nth': - var first = match[2], last = match[3]; + + case "nth": + var first = match[2], + last = match[3]; if ( first === 1 && last === 0 ) { return true; @@ -3576,33 +3736,41 @@ var Expr = Sizzle.selectors = { if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } + parent.sizcache = doneName; } var diff = elem.nodeIndex - last; + if ( first === 0 ) { return diff === 0; + } else { return ( diff % first === 0 && diff / first >= 0 ); } } }, - ID: function(elem, match){ + + ID: function( elem, match ) { return elem.nodeType === 1 && elem.getAttribute("id") === match; }, - TAG: function(elem, match){ + + TAG: function( elem, match ) { return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; }, - CLASS: function(elem, match){ + + CLASS: function( elem, match ) { return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, - ATTR: function(elem, match){ + + ATTR: function( elem, match ) { var name = match[1], result = Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : @@ -3633,8 +3801,10 @@ var Expr = Sizzle.selectors = { value === check || value.substr(0, check.length + 1) === check + "-" : false; }, - POS: function(elem, match, i, array){ - var name = match[2], filter = Expr.setFilters[ name ]; + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); @@ -3653,7 +3823,7 @@ for ( var type in Expr.match ) { Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); } -var makeArray = function(array, results) { +var makeArray = function( array, results ) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { @@ -3672,17 +3842,20 @@ try { Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; // Provide a fallback method if it does not work -} catch(e){ - makeArray = function(array, results) { - var ret = results || [], i = 0; +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); + } else { if ( typeof array.length === "number" ) { for ( var l = array.length; i < l; i++ ) { ret.push( array[i] ); } + } else { for ( ; array[i]; i++ ) { ret.push( array[i] ); @@ -3709,10 +3882,15 @@ if ( document.documentElement.compareDocumentPosition ) { return a.compareDocumentPosition(b) & 4 ? -1 : 1; }; + } else { sortOrder = function( a, b ) { - var ap = [], bp = [], aup = a.parentNode, bup = b.parentNode, - cur = aup, al, bl; + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; // The nodes are identical, we can exit early if ( a === b ) { @@ -3805,31 +3983,40 @@ Sizzle.getText = function( elems ) { (function(){ // We're going to inject a fake input element with a specified name var form = document.createElement("div"), - id = "script" + (new Date()).getTime(); + id = "script" + (new Date()).getTime(), + root = document.documentElement; + form.innerHTML = ""; // Inject it into the root element, check its status, and remove it quickly - var root = document.documentElement; root.insertBefore( form, root.firstChild ); // The workaround has to do additional checks after a getElementById // Which slows things down for other browsers (hence the branching) if ( document.getElementById( id ) ) { - Expr.find.ID = function(match, context, isXML){ + Expr.find.ID = function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); - return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; } }; - Expr.filter.ID = function(elem, match){ + Expr.filter.ID = function( elem, match ) { var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); - root = form = null; // release memory in IE + + // release memory in IE + root = form = null; })(); (function(){ @@ -3842,8 +4029,8 @@ Sizzle.getText = function( elems ) { // Make sure no comments are found if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function(match, context){ - var results = context.getElementsByTagName(match[1]); + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); // Filter out possible comments if ( match[1] === "*" ) { @@ -3864,19 +4051,25 @@ Sizzle.getText = function( elems ) { // Check to see if an attribute returns normalized href attributes div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { - Expr.attrHandle.href = function(elem){ - return elem.getAttribute("href", 2); + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); }; } - div = null; // release memory in IE + // release memory in IE + div = null; })(); if ( document.querySelectorAll ) { (function(){ - var oldSizzle = Sizzle, div = document.createElement("div"); + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + div.innerHTML = "

"; // Safari can't handle uppercase or unicode characters when @@ -3885,9 +4078,12 @@ if ( document.querySelectorAll ) { return; } - Sizzle = function(query, context, extra, seed){ + Sizzle = function( query, context, extra, seed ) { context = context || document; + // Make sure that attribute selectors are quoted + query = query.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + // Only use querySelectorAll on non-XML documents // (ID selectors don't work in non-HTML documents) if ( !seed && !Sizzle.isXML(context) ) { @@ -3901,17 +4097,19 @@ if ( document.querySelectorAll ) { // and working up from there (Thanks to Andrew Dupont for the technique) // IE 8 doesn't work on object elements } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var old = context.id, id = context.id = "__sizzle__"; + var old = context.getAttribute( "id" ), + nid = old || id; + + if ( !old ) { + context.setAttribute( "id", nid ); + } try { - return makeArray( context.querySelectorAll( "#" + id + " " + query ), extra ); + return makeArray( context.querySelectorAll( "#" + nid + " " + query ), extra ); } catch(pseudoError) { } finally { - if ( old ) { - context.id = old; - - } else { + if ( !old ) { context.removeAttribute( "id" ); } } @@ -3925,7 +4123,8 @@ if ( document.querySelectorAll ) { Sizzle[ prop ] = oldSizzle[ prop ]; } - div = null; // release memory in IE + // release memory in IE + div = null; })(); } @@ -3937,7 +4136,7 @@ if ( document.querySelectorAll ) { try { // This should fail with an exception // Gecko does not error, returns false instead - matches.call( document.documentElement, ":sizzle" ); + matches.call( document.documentElement, "[test!='']:sizzle" ); } catch( pseudoError ) { pseudoWorks = true; @@ -3945,13 +4144,18 @@ if ( document.querySelectorAll ) { if ( matches ) { Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { try { - if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) ) { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { return matches.call( node, expr ); } } catch(e) {} + } - return Sizzle(expr, null, null, [node]).length > 0; + return Sizzle(expr, null, null, [node]).length > 0; }; } })(); @@ -3975,22 +4179,25 @@ if ( document.querySelectorAll ) { } Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function(match, context, isXML) { + Expr.find.CLASS = function( match, context, isXML ) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; - div = null; // release memory in IE + // release memory in IE + div = null; })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; + if ( elem ) { - elem = elem[dir]; var match = false; + elem = elem[dir]; + while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; @@ -4018,9 +4225,11 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; + if ( elem ) { - elem = elem[dir]; var match = false; + + elem = elem[dir]; while ( elem ) { if ( elem.sizcache === doneName ) { @@ -4033,6 +4242,7 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { elem.sizcache = doneName; elem.sizset = i; } + if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; @@ -4053,21 +4263,34 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { } } -Sizzle.contains = document.documentElement.contains ? function(a, b){ - return a !== b && (a.contains ? a.contains(b) : true); -} : function(a, b){ - return !!(a.compareDocumentPosition(b) & 16); -}; +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; -Sizzle.isXML = function(elem){ +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; }; -var posProcess = function(selector, context){ - var tmpSet = [], later = "", match, +var posProcess = function( selector, context ) { + var match, + tmpSet = [], + later = "", root = context.nodeType ? [context] : context; // Position selectors must be done after the filter @@ -4109,7 +4332,8 @@ var runtil = /Until$/, jQuery.fn.extend({ find: function( selector ) { - var ret = this.pushStack( "", "find", selector ), length = 0; + var ret = this.pushStack( "", "find", selector ), + length = 0; for ( var i = 0, l = this.length; i < l; i++ ) { length = ret.length; @@ -4158,7 +4382,9 @@ jQuery.fn.extend({ var ret = [], i, l, cur = this[0]; if ( jQuery.isArray( selectors ) ) { - var match, matches = {}, selector, level = 1; + var match, selector, + matches = {}, + level = 1; if ( cur && selectors.length ) { for ( i = 0, l = selectors.length; i < l; i++ ) { @@ -4324,7 +4550,9 @@ jQuery.extend({ }, dir: function( elem, dir, until ) { - var matched = [], cur = elem[dir]; + var matched = [], + cur = elem[ dir ]; + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { matched.push( cur ); @@ -4400,7 +4628,8 @@ var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rtbody = /
\s]+\/)>/g, wrapMap = { option: [ 1, "" ], @@ -4426,7 +4655,8 @@ jQuery.fn.extend({ text: function( text ) { if ( jQuery.isFunction(text) ) { return this.each(function(i) { - var self = jQuery(this); + var self = jQuery( this ); + self.text( text.call(this, i, self.text()) ); }); } @@ -4475,7 +4705,8 @@ jQuery.fn.extend({ } return this.each(function() { - var self = jQuery( this ), contents = self.contents(); + var self = jQuery( this ), + contents = self.contents(); if ( contents.length ) { contents.wrapAll( html ); @@ -4586,7 +4817,9 @@ jQuery.fn.extend({ // attributes in IE that are actually only stored // as properties will not be copied (such as the // the name attribute on an input). - var html = this.outerHTML, ownerDocument = this.ownerDocument; + var html = this.outerHTML, + ownerDocument = this.ownerDocument; + if ( !html ) { var div = ownerDocument.createElement("div"); div.appendChild( this.cloneNode(true) ); @@ -4641,7 +4874,8 @@ jQuery.fn.extend({ } else if ( jQuery.isFunction( value ) ) { this.each(function(i){ - var self = jQuery(this); + var self = jQuery( this ); + self.html( value.call(this, i, self.html()) ); }); @@ -4664,13 +4898,14 @@ jQuery.fn.extend({ } if ( typeof value !== "string" ) { - value = jQuery(value).detach(); + value = jQuery( value ).detach(); } return this.each(function() { - var next = this.nextSibling, parent = this.parentNode; + var next = this.nextSibling, + parent = this.parentNode; - jQuery(this).remove(); + jQuery( this ).remove(); if ( next ) { jQuery(next).before( value ); @@ -4688,7 +4923,9 @@ jQuery.fn.extend({ }, domManip: function( args, table, callback ) { - var results, first, value = args[0], scripts = [], fragment, parent; + var results, first, fragment, parent, + value = args[0], + scripts = []; // We can't cloneNode fragments that contain checked, in WebKit if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) { @@ -4763,7 +5000,9 @@ function cloneCopyEvent(orig, ret) { return; } - var oldData = jQuery.data( orig[i++] ), curData = jQuery.data( this, oldData ), events = oldData && oldData.events; + var oldData = jQuery.data( orig[i++] ), + curData = jQuery.data( this, oldData ), + events = oldData && oldData.events; if ( events ) { delete curData.handle; @@ -4820,7 +5059,8 @@ jQuery.each({ replaceAll: "replaceWith" }, function( name, original ) { jQuery.fn[ name ] = function( selector ) { - var ret = [], insert = jQuery( selector ), + var ret = [], + insert = jQuery( selector ), parent = this.length === 1 && this[0].parentNode; if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) { @@ -5004,8 +5244,8 @@ var ralpha = /alpha\([^)]*\)/i, cssHeight = [ "Top", "Bottom" ], curCSS, - // cache check for defaultView.getComputedStyle - getComputedStyle = document.defaultView && document.defaultView.getComputedStyle, + getComputedStyle, + currentStyle, fcamelCase = function( all, letter ) { return letter.toUpperCase(); @@ -5161,7 +5401,29 @@ jQuery.each(["height", "width"], function( i, name ) { }); } - return val + "px"; + if ( val <= 0 ) { + val = curCSS( elem, name, name ); + + if ( val === "0px" && currentStyle ) { + val = currentStyle( elem, name, name ); + } + + if ( val != null ) { + // Should return "auto" instead of 0, use 0 for + // temporary backwards-compat + return val === "" || val === "auto" ? "0px" : val; + } + } + + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + + // Should return "auto" instead of 0, use 0 for + // temporary backwards-compat + return val === "" || val === "auto" ? "0px" : val; + } + + return typeof val === "string" ? val : val + "px"; } }, @@ -5210,8 +5472,8 @@ if ( !jQuery.support.opacity ) { }; } -if ( getComputedStyle ) { - curCSS = function( elem, newName, name ) { +if ( document.defaultView && document.defaultView.getComputedStyle ) { + getComputedStyle = function( elem, newName, name ) { var ret, defaultView, computedStyle; name = name.replace( rupper, "-$1" ).toLowerCase(); @@ -5229,10 +5491,13 @@ if ( getComputedStyle ) { return ret; }; +} -} else if ( document.documentElement.currentStyle ) { - curCSS = function( elem, name ) { - var left, rsLeft, ret = elem.currentStyle && elem.currentStyle[ name ], style = elem.style; +if ( document.documentElement.currentStyle ) { + currentStyle = function( elem, name ) { + var left, rsLeft, + ret = elem.currentStyle && elem.currentStyle[ name ], + style = elem.style; // From the awesome hack by Dean Edwards // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 @@ -5254,10 +5519,12 @@ if ( getComputedStyle ) { elem.runtimeStyle.left = rsLeft; } - return ret; + return ret === "" ? "auto" : ret; }; } +curCSS = getComputedStyle || currentStyle; + function getWH( elem, name, extra ) { var which = name === "width" ? cssWidth : cssHeight, val = name === "width" ? elem.offsetWidth : elem.offsetHeight; @@ -5284,7 +5551,8 @@ function getWH( elem, name, extra ) { if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.hidden = function( elem ) { - var width = elem.offsetWidth, height = elem.offsetHeight; + var width = elem.offsetWidth, + height = elem.offsetHeight; return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none"); }; @@ -5301,7 +5569,7 @@ var jsc = jQuery.now(), rscript = /)<[^<]*)*<\/script>/gi, rselectTextarea = /^(?:select|textarea)/i, rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, - rnoContent = /^(?:GET|HEAD|DELETE)$/, + rnoContent = /^(?:GET|HEAD)$/, rbracket = /\[\]$/, jsre = /\=\?(&|$)/, rquery = /\?/, @@ -5536,10 +5804,6 @@ jQuery.extend({ var customJsonp = window[ jsonp ]; window[ jsonp ] = function( tmp ) { - data = tmp; - jQuery.handleSuccess( s, xhr, status, data ); - jQuery.handleComplete( s, xhr, status, data ); - if ( jQuery.isFunction( customJsonp ) ) { customJsonp( tmp ); @@ -5551,6 +5815,10 @@ jQuery.extend({ delete window[ jsonp ]; } catch( jsonpError ) {} } + + data = tmp; + jQuery.handleSuccess( s, xhr, status, data ); + jQuery.handleComplete( s, xhr, status, data ); if ( head ) { head.removeChild( script ); @@ -5562,7 +5830,7 @@ jQuery.extend({ s.cache = false; } - if ( s.cache === false && type === "GET" ) { + if ( s.cache === false && noContent ) { var ts = jQuery.now(); // try replacing _= if it is there @@ -5572,8 +5840,8 @@ jQuery.extend({ s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : ""); } - // If data is available, append data to url for get requests - if ( s.data && type === "GET" ) { + // If data is available, append data to url for GET/HEAD requests + if ( s.data && noContent ) { s.url += (rquery.test(s.url) ? "&" : "?") + s.data; } @@ -5584,7 +5852,7 @@ jQuery.extend({ // Matches an absolute URL, and saves the domain var parts = rurl.exec( s.url ), - remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host); + remote = parts && (parts[1] && parts[1].toLowerCase() !== location.protocol || parts[2].toLowerCase() !== location.host); // If we're requesting a remote document // and trying to load JSON or Script with a GET @@ -5760,10 +6028,11 @@ jQuery.extend({ try { var oldAbort = xhr.abort; xhr.abort = function() { - // xhr.abort in IE7 is not a native JS function - // and does not have a call property - if ( xhr && oldAbort.call ) { - oldAbort.call( xhr ); + if ( xhr ) { + // oldAbort has no call property in IE7 so + // just do it this way, which works in all + // browsers + Function.prototype.call.call( oldAbort, xhr ); } onreadystatechange( "abort" ); @@ -5803,11 +6072,12 @@ jQuery.extend({ // Serialize an array of form elements or a set of // key/values into a query string param: function( a, traditional ) { - var s = [], add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction(value) ? value() : value; - s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value); - }; + var s = [], + add = function( key, value ) { + // If value is a function, invoke it and return its value + value = jQuery.isFunction(value) ? value() : value; + s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value); + }; // Set traditional to true for jQuery <= 1.3.2 behavior. if ( traditional === undefined ) { @@ -6029,28 +6299,39 @@ var elemdisplay = {}, jQuery.fn.extend({ show: function( speed, easing, callback ) { + var elem, display; + if ( speed || speed === 0 ) { return this.animate( genFx("show", 3), speed, easing, callback); + } else { for ( var i = 0, j = this.length; i < j; i++ ) { + elem = this[i]; + display = elem.style.display; + // Reset the inline display of this element to learn if it is // being hidden by cascaded rules or not - if ( !jQuery.data(this[i], "olddisplay") && this[i].style.display === "none" ) { - this[i].style.display = ""; + if ( !jQuery.data(elem, "olddisplay") && display === "none" ) { + display = elem.style.display = ""; } // Set elements which have been overridden with display: none // in a stylesheet to whatever the default browser style is // for such an element - if ( this[i].style.display === "" && jQuery.css( this[i], "display" ) === "none" ) { - jQuery.data(this[i], "olddisplay", defaultDisplay(this[i].nodeName)); + if ( display === "" && jQuery.css( elem, "display" ) === "none" ) { + jQuery.data(elem, "olddisplay", defaultDisplay(elem.nodeName)); } } // Set the display of most of the elements in a second loop // to avoid the constant reflow for ( i = 0; i < j; i++ ) { - this[i].style.display = jQuery.data(this[i], "olddisplay") || ""; + elem = this[i]; + display = elem.style.display; + + if ( display === "" || display === "none" ) { + elem.style.display = jQuery.data(elem, "olddisplay") || ""; + } } return this; @@ -6115,7 +6396,7 @@ jQuery.fn.extend({ } return this[ optall.queue === false ? "each" : "queue" ](function() { - // XXX ‘this’ does not always have a nodeName when running the + // XXX 'this' does not always have a nodeName when running the // test suite var opt = jQuery.extend({}, optall), p, @@ -6188,7 +6469,7 @@ jQuery.fn.extend({ } else { var parts = rfxnum.exec(val), - start = e.cur(true) || 0; + start = e.cur() || 0; if ( parts ) { var end = parseFloat( parts[2] ), @@ -6197,7 +6478,7 @@ jQuery.fn.extend({ // We need to compute starting value if ( unit !== "px" ) { jQuery.style( self, name, (end || 1) + unit); - start = ((end || 1) / e.cur(true)) * start; + start = ((end || 1) / e.cur()) * start; jQuery.style( self, name, start + unit); } @@ -6266,7 +6547,8 @@ jQuery.each({ slideUp: genFx("hide", 1), slideToggle: genFx("toggle", 1), fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" } + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } }, function( name, props ) { jQuery.fn[ name ] = function( speed, easing, callback ) { return this.animate( props, speed, easing, callback ); @@ -6344,6 +6626,9 @@ jQuery.fx.prototype = { // Start an animation from one number to another custom: function( from, to, unit ) { + var self = this, + fx = jQuery.fx; + this.startTime = jQuery.now(); this.start = from; this.end = to; @@ -6351,7 +6636,6 @@ jQuery.fx.prototype = { this.now = this.start; this.pos = this.state = 0; - var self = this, fx = jQuery.fx; function t( gotoEnd ) { return self.step(gotoEnd); } @@ -6408,7 +6692,9 @@ jQuery.fx.prototype = { if ( done ) { // Reset the overflow if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { - var elem = this.elem, options = this.options; + var elem = this.elem, + options = this.options; + jQuery.each( [ "", "X", "Y" ], function (index, value) { elem.style[ "overflow" + value ] = options.overflow[index]; } ); @@ -6587,11 +6873,16 @@ if ( "getBoundingClientRect" in document.documentElement ) { jQuery.offset.initialize(); - var offsetParent = elem.offsetParent, prevOffsetParent = elem, - doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement, - body = doc.body, defaultView = doc.defaultView, + var computedStyle, + offsetParent = elem.offsetParent, + prevOffsetParent = elem, + doc = elem.ownerDocument, + docElem = doc.documentElement, + body = doc.body, + defaultView = doc.defaultView, prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle, - top = elem.offsetTop, left = elem.offsetLeft; + top = elem.offsetTop, + left = elem.offsetLeft; while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) { if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { @@ -6673,7 +6964,8 @@ jQuery.offset = { }, bodyOffset: function( body ) { - var top = body.offsetTop, left = body.offsetLeft; + var top = body.offsetTop, + left = body.offsetLeft; jQuery.offset.initialize(); @@ -6854,27 +7146,31 @@ jQuery.each([ "Height", "Width" ], function( i, name ) { }); } - return jQuery.isWindow( elem ) ? + if ( jQuery.isWindow( elem ) ) { // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode - elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] || - elem.document.body[ "client" + name ] : - - // Get document width or height - (elem.nodeType === 9) ? // is it a document - // Either scroll[Width/Height] or offset[Width/Height], whichever is greater - Math.max( - elem.documentElement["client" + name], - elem.body["scroll" + name], elem.documentElement["scroll" + name], - elem.body["offset" + name], elem.documentElement["offset" + name] - ) : - - // Get or set width or height on the element - size === undefined ? - // Get width or height on the element - parseFloat( jQuery.css( elem, type ) ) : - - // Set the width or height on the element (default to pixels if value is unitless) - this.css( type, typeof size === "string" ? size : size + "px" ); + return elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] || + elem.document.body[ "client" + name ]; + + // Get document width or height + } else if ( elem.nodeType === 9 ) { + // Either scroll[Width/Height] or offset[Width/Height], whichever is greater + return Math.max( + elem.documentElement["client" + name], + elem.body["scroll" + name], elem.documentElement["scroll" + name], + elem.body["offset" + name], elem.documentElement["offset" + name] + ); + + // Get or set width or height on the element + } else if ( size === undefined ) { + var orig = jQuery.css( elem, type ), + ret = parseFloat( orig ); + + return jQuery.isNaN( ret ) ? orig : ret; + + // Set the width or height on the element (default to pixels if value is unitless) + } else { + return this.css( type, typeof size === "string" ? size : size + "px" ); + } }; }); -- cgit v1.2.3 From 983976ec5484b92d1b46305a2e3bd59bf98a3853 Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Sat, 13 Nov 2010 06:29:30 +0800 Subject: Finder gives a little bit more info on the lookup column (primary key) --- activerecord/lib/active_record/relation/finder_methods.rb | 2 +- activerecord/test/cases/finder_test.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index e9e9c85122..4192456447 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -300,7 +300,7 @@ module ActiveRecord unless record conditions = arel.where_sql conditions = " [#{conditions}]" if conditions - raise RecordNotFound, "Couldn't find #{@klass.name} with ID=#{id}#{conditions}" + raise RecordNotFound, "Couldn't find #{@klass.name} with #{@klass.primary_key}=#{id}#{conditions}" end record diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 87ec999b03..39ce47d9d6 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -10,6 +10,7 @@ require 'models/entrant' require 'models/project' require 'models/developer' require 'models/customer' +require 'models/toy' class FinderTest < ActiveRecord::TestCase fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers, :categories, :categorizations @@ -1010,6 +1011,15 @@ class FinderTest < ActiveRecord::TestCase end end + def test_find_one_message_with_custom_primary_key + Toy.set_primary_key :name + begin + Toy.find 'Hello World!' + rescue ActiveRecord::RecordNotFound => e + assert_equal 'Couldn\'t find Toy with name=Hello World!', e.message + end + end + protected def bind(statement, *vars) if vars.first.is_a?(Hash) -- cgit v1.2.3 From 7cc371a032214afbfab94e756d82a3058e3a7e02 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 12 Nov 2010 18:36:42 -0600 Subject: Allow bundler 1.1 (and 1.2, etc.) in Rails 1.0.2 and above --- rails.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rails.gemspec b/rails.gemspec index d791e21ec2..98b5f46554 100644 --- a/rails.gemspec +++ b/rails.gemspec @@ -25,5 +25,5 @@ Gem::Specification.new do |s| s.add_dependency('activeresource', version) s.add_dependency('actionmailer', version) s.add_dependency('railties', version) - s.add_dependency('bundler', '~> 1.0.3') + s.add_dependency('bundler', '~> 1.0') end -- cgit v1.2.3 From b235519777b921c0ecf4e20fbeb5f5fe49459775 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sat, 13 Nov 2010 11:15:17 +0800 Subject: Add documentation for the mount method in ActionDispatch's Mapper --- actionpack/lib/action_dispatch/routing/mapper.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 2b3c20f6b9..c3f778a70f 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -262,6 +262,23 @@ module ActionDispatch self end + # Mount a Rack-based application to be used within the application. + # + # mount SomeRackApp, :at => "some_route" + # + # Alternatively: + # + # mount(SomeRackApp => "some_route") + # + # All mounted applications come with routing helpers to access them. + # These are named after the class specified, so for the above example + # the helper is either +some_rack_app_path+ or +some_rack_app_url+. + # To customize this helper's name, use the +:as+ option: + # + # mount(SomeRackApp => "some_route", :as => "exciting") + # + # This will generate the +exciting_path+ and +exciting_url+ helpers + # which can be used to navigate to this mounted app. def mount(app, options = nil) if options path = options.delete(:at) -- cgit v1.2.3 From 95f41fe12e7680459351be633a171abf26beac1a Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sat, 13 Nov 2010 11:16:06 +0800 Subject: See the scope method for documentation for namespace's shallow_path option --- actionpack/lib/action_dispatch/routing/mapper.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index c3f778a70f..cc013ac072 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -625,6 +625,9 @@ module ActionDispatch # end # # Routing helpers such as +admin_posts_path+ will now be +sekret_posts_path+. + # + # [:shallow_path] + # See the +scope+ method. def namespace(path, options = {}) path = path.to_s options = { :path => path, :as => path, :module => path, -- cgit v1.2.3 From fe8446fcced912730b068944b2ce152f18046f77 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sat, 13 Nov 2010 11:16:32 +0800 Subject: Add documentation for :path_names option on resources --- actionpack/lib/action_dispatch/routing/mapper.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index cc013ac072..8b5d7d307b 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -911,6 +911,14 @@ module ActionDispatch # GET /photos/:id/edit # PUT /photos/:id # DELETE /photos/:id + # === Supported options + # [:path_names] + # Allows you to change the paths of the seven default actions. + # Paths not specified are not changed. + # + # resources :posts, :path_names => { :new => "brand_new" } + # + # The above example will now change /posts/new to /posts/brand_new def resources(*resources, &block) options = resources.extract_options! -- cgit v1.2.3 From 27f4ffd11a91b534fde9b484cb7c4e515ec0fe77 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 13 Nov 2010 04:01:10 -0200 Subject: Make collection and collection_from_object methods return an array This transforms for instance scoped objects into arrays and avoid unneeded queries [#5958 state:committed] --- actionpack/lib/action_view/renderer/partial_renderer.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index c580397cad..317479ad4c 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -90,13 +90,14 @@ module ActionView def collection if @options.key?(:collection) - @options[:collection] || [] + collection = @options[:collection] + collection.respond_to?(:to_ary) ? collection.to_ary : [] end end def collection_from_object if @object.respond_to?(:to_ary) - @object + @object.to_ary end end @@ -163,4 +164,4 @@ module ActionView [variable, variable_counter] end end -end \ No newline at end of file +end -- cgit v1.2.3 From d44cd370bfd044d460359ec8c2bb5ce36451d341 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Sat, 13 Nov 2010 12:17:21 +0100 Subject: colorize_logging is a Rails General Configuration option not a specific option of ActiveRecord --- railties/guides/source/configuring.textile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index bb38c64307..28fff5c11e 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -32,7 +32,7 @@ config.filter_parameters << :password This is a setting for Rails itself. If you want to pass settings to individual Rails components, you can do so via the same +config+ object: -config.active_record.colorize_logging = false +config.active_record.timestamped_migrations = false Rails will use that particular setting to configure Active Record. @@ -45,6 +45,8 @@ h4. Rails General Configuration * +config.cache_store+ configures which cache store to use for Rails caching. Options include +:memory_store+, +:file_store+, +:mem_cache_store+ or the name of your own custom class. +* +config.colorize_logging+ (true by default) specifies whether or not to use ANSI color codes when logging information. + * +config.controller_paths+ accepts an array of paths that will be searched for controllers. Defaults to +app/controllers+. * +config.database_configuration_file+ overrides the default path for the database configuration file. Default to +config/database.yml+. @@ -105,8 +107,6 @@ h4. Configuring Active Record * +config.active_record.pluralize_table_names+ specifies whether Rails will look for singular or plural table names in the database. If set to +true+ (the default), then the Customer class will use the +customers+ table. If set to +false+, then the Customers class will use the +customer+ table. -* +config.active_record.colorize_logging+ (true by default) specifies whether or not to use ANSI color codes when logging information from ActiveRecord. - * +config.active_record.default_timezone+ determines whether to use +Time.local+ (if set to +:local+) or +Time.utc+ (if set to +:utc+) when pulling dates and times from the database. The default is +:local+. * +config.active_record.schema_format+ controls the format for dumping the database schema to a file. The options are +:ruby+ (the default) for a database-independent version that depends on migrations, or +:sql+ for a set of (potentially database-dependent) SQL statements. -- cgit v1.2.3 From e3b68e5f6bbdd782ae37ee0f043f0d738f518dd2 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 13 Nov 2010 13:38:40 -0200 Subject: Tests added for rendering partial with layout, when the partial contains another render layout with block call --- actionpack/test/template/render_test.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 08d50257d4..d2bf45a63a 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -277,6 +277,21 @@ module RenderTestCases @view.render(:partial => 'test/partial_with_partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) end + def test_render_layout_with_a_nested_render_layout_call + assert_equal %(Before (Foo!)\nBefore (Bar!)\npartial html\nAfter\npartial with layout\n\nAfter), + @view.render(:partial => 'test/partial_with_layout', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_layout_with_a_nested_render_layout_call_using_block_with_render_partial + assert_equal %(Before (Foo!)\nBefore (Bar!)\n\n partial html\n\nAfterpartial with layout\n\nAfter), + @view.render(:partial => 'test/partial_with_layout_block_partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_layout_with_a_nested_render_layout_call_using_block_with_render_content + assert_equal %(Before (Foo!)\nBefore (Bar!)\n\n Content from inside layout!\n\nAfterpartial with layout\n\nAfter), + @view.render(:partial => 'test/partial_with_layout_block_content', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + def test_render_with_nested_layout assert_equal %(title\n\n
column
\n
content
\n), @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") -- cgit v1.2.3 From 293c8a4de5bfe3274e0fda7dfab1b6ec296bb829 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 13 Nov 2010 13:40:36 -0200 Subject: Tests added for rendering partial with layout, when the partial contains another render layout with block call added missing fixtures --- actionpack/test/fixtures/test/_partial_with_layout.erb | 2 ++ actionpack/test/fixtures/test/_partial_with_layout_block_content.erb | 4 ++++ actionpack/test/fixtures/test/_partial_with_layout_block_partial.erb | 4 ++++ 3 files changed, 10 insertions(+) create mode 100644 actionpack/test/fixtures/test/_partial_with_layout.erb create mode 100644 actionpack/test/fixtures/test/_partial_with_layout_block_content.erb create mode 100644 actionpack/test/fixtures/test/_partial_with_layout_block_partial.erb diff --git a/actionpack/test/fixtures/test/_partial_with_layout.erb b/actionpack/test/fixtures/test/_partial_with_layout.erb new file mode 100644 index 0000000000..2a50c834fe --- /dev/null +++ b/actionpack/test/fixtures/test/_partial_with_layout.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'test/partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Bar!' } %> +partial with layout diff --git a/actionpack/test/fixtures/test/_partial_with_layout_block_content.erb b/actionpack/test/fixtures/test/_partial_with_layout_block_content.erb new file mode 100644 index 0000000000..65dafd93a8 --- /dev/null +++ b/actionpack/test/fixtures/test/_partial_with_layout_block_content.erb @@ -0,0 +1,4 @@ +<%= render :layout => 'test/layout_for_partial', :locals => { :name => 'Bar!' } do %> + Content from inside layout! +<% end %> +partial with layout diff --git a/actionpack/test/fixtures/test/_partial_with_layout_block_partial.erb b/actionpack/test/fixtures/test/_partial_with_layout_block_partial.erb new file mode 100644 index 0000000000..444197a7d0 --- /dev/null +++ b/actionpack/test/fixtures/test/_partial_with_layout_block_partial.erb @@ -0,0 +1,4 @@ +<%= render :layout => 'test/layout_for_partial', :locals => { :name => 'Bar!' } do %> + <%= render 'test/partial' %> +<% end %> +partial with layout -- cgit v1.2.3 From 74061f55be2ba83f1457369b7e47cab54d26a57f Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sun, 14 Nov 2010 07:32:54 +0800 Subject: Document the constraints method --- actionpack/lib/action_dispatch/routing/mapper.rb | 56 +++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 8b5d7d307b..2eb2af7a11 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -634,7 +634,61 @@ module ActionDispatch :shallow_path => path, :shallow_prefix => path }.merge!(options) scope(options) { yield } end - + + # === Parameter Restriction + # Allows you to constrain the nested routes based on a set of rules. + # For instance, in order to change the routes to allow for a dot character in the +id+ parameter: + # + # constraints(:id => /\d+\.\d+) do + # resources :posts + # end + # + # Now routes such as +/posts/1+ will no longer be valid, but +/posts/1.1+ will be. + # The +id+ parameter must match the constraint passed in for this example. + # + # You may use this to also resrict other parameters: + # + # resources :posts do + # constraints(:post_id => /\d+\.\d+) do + # resources :comments + # end + # + # === Restricting based on IP + # + # Routes can also be constrained to an IP or a certain range of IP addresses: + # + # constraints(:ip => /192.168.\d+.\d+/) do + # resources :posts + # end + # + # Any user connecting from the 192.168.* range will be able to see this resource, + # where as any user connecting outside of this range will be told there is no such route. + # + # === Dynamic request matching + # + # Requests to routes can be constrained based on specific critera: + # + # constraints(lambda { |req| req.env["HTTP_USER_AGENT"] =~ /iPhone/ }) do + # resources :iphones + # end + # + # You are able to move this logic out into a class if it is too complex for routes. + # This class must have a +matches?+ method defined on it which either returns +true+ + # if the user should be given access to that route, or +false+ if the user should not. + # + # class Iphone + # def self.matches(request) + # request.env["HTTP_USER_AGENT"] =~ /iPhone/ + # end + # end + # + # An expected place for this code would be +lib/constraints+. + # + # This class is then used like this: + # + # constraints(Iphone) do + # resources :iphones + # end def constraints(constraints = {}) scope(:constraints => constraints) { yield } end -- cgit v1.2.3 From 7e1f6688e92c18f9973ad65db7b95de495b98947 Mon Sep 17 00:00:00 2001 From: Rajinder Yadav Date: Sat, 13 Nov 2010 20:24:04 -0500 Subject: the partial option is not required for simple partial rendering --- railties/guides/source/layouts_and_rendering.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile index c65ea5c797..4e26d152bf 100644 --- a/railties/guides/source/layouts_and_rendering.textile +++ b/railties/guides/source/layouts_and_rendering.textile @@ -970,7 +970,7 @@ Partial templates - usually just called "partials" - are another device for brea h5. Naming Partials -To render a partial as part of a view, you use the +render+ method within the view, and include the +:partial+ option: +To render a partial as part of a view, you use the +render+ method within the view: <%= render "menu" %> -- cgit v1.2.3 From f43e5d160bf9708ad50b58c8168e38579769e024 Mon Sep 17 00:00:00 2001 From: Larry Sprock Date: Sun, 14 Nov 2010 15:01:14 +0800 Subject: HashWithIndifferentAccess should not change the subclass of an array --- .../lib/active_support/hash_with_indifferent_access.rb | 2 +- activesupport/test/core_ext/hash_ext_test.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 06dd18966e..320f5c1c92 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -144,7 +144,7 @@ module ActiveSupport when Hash self.class.new_from_hash_copying_default(value) when Array - value.collect { |e| e.is_a?(Hash) ? self.class.new_from_hash_copying_default(e) : e } + value.dup.replace(value.collect { |e| e.is_a?(Hash) ? self.class.new_from_hash_copying_default(e) : e }) else value end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index d7b77e43bd..370f26b0d7 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -8,6 +8,9 @@ require 'active_support/core_ext/object/conversions' class HashExtTest < Test::Unit::TestCase class IndifferentHash < HashWithIndifferentAccess end + + class SubclassingArray < Array + end def setup @strings = { 'a' => 1, 'b' => 2 } @@ -251,6 +254,20 @@ class HashExtTest < Test::Unit::TestCase hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access assert_equal "1", hash[:urls][:url].first[:address] end + + def test_should_preserve_array_subclass_when_value_is_array + array = SubclassingArray.new + array << { "address" => "1" } + hash = { "urls" => { "url" => array }}.with_indifferent_access + assert_equal SubclassingArray, hash[:urls][:url].class + end + + def test_should_preserve_array_class_when_hash_value_is_frozen_array + array = SubclassingArray.new + array << { "address" => "1" } + hash = { "urls" => { "url" => array.freeze }}.with_indifferent_access + assert_equal SubclassingArray, hash[:urls][:url].class + end def test_stringify_and_symbolize_keys_on_indifferent_preserves_hash h = HashWithIndifferentAccess.new -- cgit v1.2.3 From e6d14279b881d8482c124bd55d0830a7ddcbcb0e Mon Sep 17 00:00:00 2001 From: raggi Date: Wed, 27 Oct 2010 06:10:01 +0800 Subject: Add support for try to just yield the object to a block if no method is to be called. Kind of like a tap_if_present. --- activesupport/lib/active_support/core_ext/object/try.rb | 14 +++++++++++++- activesupport/test/core_ext/object_and_class_ext_test.rb | 10 ++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb index 48e9d04787..4d742b9ed2 100644 --- a/activesupport/lib/active_support/core_ext/object/try.rb +++ b/activesupport/lib/active_support/core_ext/object/try.rb @@ -8,6 +8,8 @@ class Object # *Unlike* that method however, a +NoMethodError+ exception will *not* be raised # and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass. # + # If try is called without a method to call, it will yield any given block with the object. + # # ==== Examples # # Without try @@ -21,10 +23,20 @@ class Object # +try+ also accepts arguments and/or a block, for the method it is trying # Person.try(:find, 1) # @people.try(:collect) {|p| p.name} + # + # Without a method argument try will yield to the block unless the reciever is nil. + # @person.try { |p| "#{p.first_name} #{p.last_name}" } #-- # +try+ behaves like +Object#send+, unless called on +NilClass+. - alias_method :try, :__send__ + def try(*a, &b) + if a.empty? && block_given? + yield self + else + __send__(*a, &b) + end + end + end class NilClass #:nodoc: diff --git a/activesupport/test/core_ext/object_and_class_ext_test.rb b/activesupport/test/core_ext/object_and_class_ext_test.rb index 64f339ed90..398e6ca9b2 100644 --- a/activesupport/test/core_ext/object_and_class_ext_test.rb +++ b/activesupport/test/core_ext/object_and_class_ext_test.rb @@ -134,4 +134,14 @@ class ObjectTryTest < Test::Unit::TestCase def test_false_try assert_equal 'false', false.try(:to_s) end + + def test_try_only_block + assert_equal @string.reverse, @string.try { |s| s.reverse } + end + + def test_try_only_block_nil + ran = false + nil.try { ran = true } + assert_equal false, ran + end end -- cgit v1.2.3 From 88688cdd8e467d4bdebfa3f08e47cd5e7c5ead2c Mon Sep 17 00:00:00 2001 From: Robert Pankowecki Date: Sun, 24 Oct 2010 17:44:17 +0800 Subject: Fix when database column name has some symbolic characters. [#5818 state:resolved] --- activemodel/lib/active_model/attribute_methods.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index 44e3e64a9e..c1c5640616 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -98,10 +98,10 @@ module ActiveModel def define_attr_method(name, value=nil, &block) sing = singleton_class sing.class_eval <<-eorb, __FILE__, __LINE__ + 1 - if method_defined?(:original_#{name}) - undef :original_#{name} + if method_defined?(:'original_#{name}') + undef :'original_#{name}' end - alias_method :original_#{name}, :#{name} + alias_method :'original_#{name}', :'#{name}' eorb if block_given? sing.send :define_method, name, &block @@ -274,8 +274,8 @@ module ActiveModel method_name = matcher.method_name(attr_name) generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 - if method_defined?(:#{method_name}) - undef :#{method_name} + if method_defined?(:'#{method_name}') + undef :'#{method_name}' end def #{method_name}(*args) send(:#{matcher.method_missing_target}, '#{attr_name}', *args) -- cgit v1.2.3 From 23f71c431dae9ec389a861700ea84c7b0cbf913c Mon Sep 17 00:00:00 2001 From: Rajinder Yadav Date: Sun, 14 Nov 2010 05:12:01 -0500 Subject: corrected sample code to clear @_current_user class variable also --- railties/guides/source/action_controller_overview.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index c02e9f1912..3774c7fcf5 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -239,7 +239,7 @@ class LoginsController < ApplicationController # "Delete" a login, aka "log the user out" def destroy # Remove the user id from the session - session[:current_user_id] = nil + @_current_user = session[:current_user_id] = nil redirect_to root_url end end -- cgit v1.2.3 From f69784289b6efd0eabb674d6467b2cd0c0a4af07 Mon Sep 17 00:00:00 2001 From: Rajinder Yadav Date: Sun, 14 Nov 2010 05:20:10 -0500 Subject: added note with example for using flash in redirection --- railties/guides/source/action_controller_overview.textile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index 3774c7fcf5..cabc0c8a7f 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -261,6 +261,13 @@ class LoginsController < ApplicationController end +Note it is also possible to assign a flash message as part of the redirection. + + + redirect_to root_url, :notice => "You have successfully logged out" + + + The +destroy+ action redirects to the application's +root_url+, where the message will be displayed. Note that it's entirely up to the next action to decide what, if anything, it will do with what the previous action put in the flash. It's conventional to display eventual errors or notices from the flash in the application's layout: -- cgit v1.2.3 From abf225423cbe11fcb0460a40bd49263694eaef06 Mon Sep 17 00:00:00 2001 From: Rajinder Yadav Date: Sun, 14 Nov 2010 06:02:16 -0500 Subject: removed unnecessary indentation --- railties/guides/source/action_controller_overview.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index cabc0c8a7f..b39075f101 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -264,7 +264,7 @@ end Note it is also possible to assign a flash message as part of the redirection. - redirect_to root_url, :notice => "You have successfully logged out" +redirect_to root_url, :notice => "You have successfully logged out" -- cgit v1.2.3 From 330d65d31222148019855d6914e35c8cd9f90cd5 Mon Sep 17 00:00:00 2001 From: Aditya Sanghi Date: Sun, 14 Nov 2010 18:27:08 +0530 Subject: deliver_* is no more --- railties/guides/source/action_mailer_basics.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index 41738827b2..8d2ce44e93 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -446,7 +446,7 @@ The following configuration options are best made in one of the environment file |sendmail_settings|Allows you to override options for the :sendmail delivery method.
  • :location - The location of the sendmail executable. Defaults to /usr/sbin/sendmail.
  • :arguments - The command line arguments to be passed to sendmail. Defaults to -i -t.
| |raise_delivery_errors|Whether or not errors should be raised if the email fails to be delivered.| |delivery_method|Defines a delivery method. Possible values are :smtp (default), :sendmail, :file and :test.| -|perform_deliveries|Determines whether deliver_* methods are actually carried out. By default they are, but this can be turned off to help functional testing.| +|perform_deliveries|Determines whether deliveries are actually carried out when the +deliver+ method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.| |deliveries|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.| h4. Example Action Mailer Configuration -- cgit v1.2.3 From fae4264a7efe2df4890b5f1095bd7454e3bcb939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 14 Nov 2010 16:22:21 +0100 Subject: Update the guides. --- railties/guides/source/active_support_core_extensions.textile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 8c11b2a11a..dc1200812e 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -167,6 +167,12 @@ def log_info(sql, name, ms) end
++try+ can also be called without arguments but a block, which will only be executed if the object is not nil: + + +@person.try { |p| "#{p.first_name} #{p.last_name}" } + + NOTE: Defined in +active_support/core_ext/object/try.rb+. h4. +singleton_class+ -- cgit v1.2.3 From 93c9f4a942c622ecbe8d46ab4838bd072aef9fc0 Mon Sep 17 00:00:00 2001 From: Jason Cheow Date: Sun, 14 Nov 2010 13:55:36 +0800 Subject: Fix bug where size of through association is not correct after adding a has_many association (occurs only before main object has been reloaded). [#5968 state:committed] Signed-off-by: Santiago Pastorino --- .../lib/active_record/associations/has_many_through_association.rb | 1 - .../test/cases/associations/has_many_through_associations_test.rb | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 51770cff0f..0a5858f36e 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -69,7 +69,6 @@ module ActiveRecord through_association = @owner.send(@reflection.through_reflection.name) through_record = through_association.create!(construct_join_attributes(record)) - through_association.proxy_target << through_record end # TODO - add dependent option support diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 4b9f49f1ec..94e1eb8c89 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -449,4 +449,11 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase comment = post.comments.build assert author.comments.include?(comment) end + + def test_size_of_through_association_should_increase_correctly_when_has_many_association_is_added + post = posts(:thinking) + readers = post.readers.size + post.people << people(:michael) + assert_equal readers + 1, post.readers.size + end end -- cgit v1.2.3 From bc556a21e2d5722f42dfac810c04d453076e09fb Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 14 Nov 2010 15:34:07 -0200 Subject: Remove unused var --- .../lib/active_record/associations/has_many_through_association.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 0a5858f36e..79c229d9c4 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -68,7 +68,7 @@ module ActiveRecord end through_association = @owner.send(@reflection.through_reflection.name) - through_record = through_association.create!(construct_join_attributes(record)) + through_association.create!(construct_join_attributes(record)) end # TODO - add dependent option support -- cgit v1.2.3 From c996901913d74640afb1856044e5a5d6bd12a7fd Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 14 Nov 2010 21:00:26 -0200 Subject: Change deprecated syntax and use f.submit instead of submit_tag --- railties/guides/source/form_helpers.textile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index 80e0421b48..35b9d486b9 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/guides/source/form_helpers.textile @@ -232,13 +232,13 @@ The corresponding view +app/views/articles/new.html.erb+ using +form_for+ looks <%= form_for @article, :url => { :action => "create" }, :html => {:class => "nifty_form"} do |f| %> <%= f.text_field :title %> <%= f.text_area :body, :size => "60x12" %> - <%= submit_tag "Create" %> + <%= f.submit "Create" %> <% end %> There are a few things to note here: -# +:article+ is the name of the model and +@article+ is the actual object being edited. +# +@article+ is the actual object being edited. # There is a single hash of options. Routing options are passed in the +:url+ hash, HTML options are passed in the +:html+ hash. # The +form_for+ method yields a *form builder* object (the +f+ variable). # Methods to create form controls are called *on* the form builder object +f+ @@ -294,13 +294,13 @@ When dealing with RESTful resources, calls to +form_for+ can get significantly e ## Creating a new article # long-style: -form_for(:article, @article, :url => articles_path) +form_for(@article, :url => articles_path) # same thing, short-style (record identification gets used): form_for(@article) ## Editing an existing article # long-style: -form_for(:article, @article, :url => article_path(@article), :html => { :method => "put" }) +form_for(@article, :url => article_path(@article), :html => { :method => "put" }) # short-style: form_for(@article) -- cgit v1.2.3 From 4ef6d2e534e4d470290e1454d51312fa5f8b3b0c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 14 Nov 2010 21:01:59 -0200 Subject: Add empty line between previous method and RDoc of submit to allow RDoc appear on api.rubyonrails.org --- actionpack/lib/action_view/helpers/form_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 0470b051c6..b8a4b0c9cb 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1205,6 +1205,7 @@ module ActionView self.multipart = true @template.file_field(@object_name, method, objectify_options(options)) end + # Add the submit button for the given form. When no value is given, it checks # if the object is a new resource or not to create the proper label: # -- cgit v1.2.3 From 324569bb113ab6525d3eb1d5e35fa6bc911917eb Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Mon, 15 Nov 2010 00:07:25 +0100 Subject: Getting Started guide: remove calls to f.error_messages as it has been removed from Rails --- railties/guides/source/getting_started.textile | 8 -------- 1 file changed, 8 deletions(-) diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index e592417dcb..f3420e37d1 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -919,8 +919,6 @@ So first, we'll wire up the Post show template (+/app/views/posts/show.html.erb+

Add a comment:

<%= form_for([@post, @post.comments.build]) do |f| %> - <%= f.error_messages %> -
<%= f.label :commenter %>
<%= f.text_field :commenter %> @@ -989,8 +987,6 @@ Once we have made the new comment, we send the user back to the original post us

Add a comment:

<%= form_for([@post, @post.comments.build]) do |f| %> - <%= f.error_messages %> -
<%= f.label :commenter %>
<%= f.text_field :commenter %> @@ -1057,8 +1053,6 @@ Then in the +app/views/posts/show.html.erb+ you can change it to look like the f

Add a comment:

<%= form_for([@post, @post.comments.build]) do |f| %> - <%= f.error_messages %> -
<%= f.label :commenter %>
<%= f.text_field :commenter %> @@ -1086,8 +1080,6 @@ Lets also move that new comment section out to it's own partial, again, you crea <%= form_for([@post, @post.comments.build]) do |f| %> - <%= f.error_messages %> -
<%= f.label :commenter %>
<%= f.text_field :commenter %> -- cgit v1.2.3 From f597d1ec8097d98198a58cb932c2c202c5f0a931 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 14 Nov 2010 21:25:37 -0200 Subject: This doesn't make sense here --- actionpack/lib/action_view/helpers/form_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 0470b051c6..9dd763050c 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -269,8 +269,8 @@ module ActionView # <%= form_for @person, :url => { :action => "create" }, :builder => LabellingFormBuilder do |f| %> # <%= f.text_field :first_name %> # <%= f.text_field :last_name %> - # <%= text_area :person, :biography %> - # <%= check_box_tag "person[admin]", @person.company.admin? %> + # <%= f.text_area :biography %> + # <%= f.check_box :admin %> # <% end %> # # In this case, if you use this: -- cgit v1.2.3 From 0262218976b29630c9a2b77cf3cf03deae21614f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 14 Nov 2010 21:40:34 -0200 Subject: Add f.submit to forms just to show the most common use case --- actionpack/lib/action_view/helpers/form_helper.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index f77b138bc6..8c300ec745 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -112,6 +112,7 @@ module ActionView # <%= f.text_field :version %>
# <%= f.label :author, 'Author' %>: # <%= f.text_field :author %>
+ # <%= f.submit %> # <% end %> # # There, +form_for+ is able to generate the rest of RESTful form @@ -129,6 +130,7 @@ module ActionView # Last name : <%= f.text_field :last_name %>
# Biography : <%= f.text_area :biography %>
# Admin? : <%= f.check_box :admin %>
+ # <%= f.submit %> # <% end %> # # There, the argument is a symbol or string with the name of the @@ -160,6 +162,7 @@ module ActionView # Last name : <%= f.text_field :last_name %> # Biography : <%= text_area :person, :biography %> # Admin? : <%= check_box_tag "person[admin]", @person.company.admin? %> + # <%= f.submit %> # <% end %> # # This also works for the methods in FormOptionHelper and DateHelper that @@ -271,6 +274,7 @@ module ActionView # <%= f.text_field :last_name %> # <%= f.text_area :biography %> # <%= f.check_box :admin %> + # <%= f.submit %> # <% end %> # # In this case, if you use this: @@ -347,6 +351,8 @@ module ActionView # <%= fields_for @person.permission do |permission_fields| %> # Admin? : <%= permission_fields.check_box :admin %> # <% end %> + # + # <%= f.submit %> # <% end %> # # ...or if you have an object that needs to be represented as a different @@ -408,6 +414,7 @@ module ActionView # Street : <%= address_fields.text_field :street %> # Zip code: <%= address_fields.text_field :zip_code %> # <% end %> + # ... # <% end %> # # When address is already an association on a Person you can use @@ -437,6 +444,7 @@ module ActionView # ... # Delete: <%= address_fields.check_box :_destroy %> # <% end %> + # ... # <% end %> # # ==== One-to-many @@ -466,6 +474,7 @@ module ActionView # Name: <%= project_fields.text_field :name %> # <% end %> # <% end %> + # ... # <% end %> # # It's also possible to specify the instance to be used: @@ -479,6 +488,7 @@ module ActionView # <% end %> # <% end %> # <% end %> + # ... # <% end %> # # Or a collection to be used: @@ -488,6 +498,7 @@ module ActionView # <%= person_form.fields_for :projects, @active_projects do |project_fields| %> # Name: <%= project_fields.text_field :name %> # <% end %> + # ... # <% end %> # # When projects is already an association on Person you can use @@ -517,6 +528,7 @@ module ActionView # <%= person_form.fields_for :projects do |project_fields| %> # Delete: <%= project_fields.check_box :_destroy %> # <% end %> + # ... # <% end %> def fields_for(record, record_object = nil, options = nil, &block) capture(instantiate_builder(record, record_object, options, &block), &block) -- cgit v1.2.3 From e7de5dd11e04f03e32865be8bb8c090a96a79ec9 Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Tue, 16 Nov 2010 00:08:04 +1100 Subject: Bump up mail dependency to take advantage of relaxed i18n version requirement --- actionmailer/actionmailer.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 29b5813785..aaa71d20c4 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |s| s.has_rdoc = true s.add_dependency('actionpack', version) - s.add_dependency('mail', '~> 2.2.9') + s.add_dependency('mail', '~> 2.2.9.1') end -- cgit v1.2.3 From 8124b2bc24b8312ee4d1ce2f133bf6e2dd87ad49 Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Tue, 16 Nov 2010 00:23:03 +1100 Subject: Revert "Bump up mail dependency to take advantage of relaxed i18n version requirement" Locking to ~> 2.2.9.1 means locking to < 2.2.10, not intended behaviour. This reverts commit e7de5dd11e04f03e32865be8bb8c090a96a79ec9. --- actionmailer/actionmailer.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index aaa71d20c4..29b5813785 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |s| s.has_rdoc = true s.add_dependency('actionpack', version) - s.add_dependency('mail', '~> 2.2.9.1') + s.add_dependency('mail', '~> 2.2.9') end -- cgit v1.2.3 From c2c2b8b96220b11eb3512b1eaaf7985c84f03d67 Mon Sep 17 00:00:00 2001 From: James Miller Date: Mon, 15 Nov 2010 09:26:57 -0700 Subject: Add HTTP Verb Constraints (:via) to routing guide --- railties/guides/source/routing.textile | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index f48ae9c7f7..cc0c3316c8 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -436,6 +436,26 @@ match 'exit' => 'sessions#destroy', :as => :logout This will create +logout_path+ and +logout_url+ as named helpers in your application. Calling +logout_path+ will return +/exit+ +h4. HTTP Verb Constraints + +You can use the +:via+ option to constrain the request to one or more HTTP methods: + + +match 'photos/show' => 'photos#show', :via => :get + + +There is a shorthand version of this as well: + + +get 'photos/show' + + +You can also permit more than one verb to a single route: + + +match 'photos/show' => 'photos#show', :via => [:get, :post] + + h4. Segment Constraints You can use the +:constraints+ option to enforce a format for a dynamic segment: -- cgit v1.2.3 From 022519a032c830afa1fa1b9d02a27acf5588476b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 15 Nov 2010 10:12:09 -0800 Subject: fisting a bunch of unused variable warnings --- .../eager_load_includes_full_sti_class_test.rb | 2 +- activerecord/test/cases/associations/eager_test.rb | 12 ++++++------ .../has_and_belongs_to_many_associations_test.rb | 6 ++---- .../cases/associations/has_many_associations_test.rb | 16 +++++++--------- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb index b124a2bfc3..fb59f63f91 100644 --- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb +++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb @@ -17,7 +17,7 @@ class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase def generate_test_objects post = Namespaced::Post.create( :title => 'Great stuff', :body => 'This is not', :author_id => 1 ) - tagging = Tagging.create( :taggable => post ) + Tagging.create( :taggable => post ) end def test_class_names diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index b559c9ddad..66fb5ac1e1 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -323,7 +323,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_has_many_through_a_belongs_to_association author = authors(:mary) - post = Post.create!(:author => author, :title => "TITLE", :body => "BODY") + Post.create!(:author => author, :title => "TITLE", :body => "BODY") author.author_favorites.create(:favorite_author_id => 1) author.author_favorites.create(:favorite_author_id => 2) posts_with_author_favorites = author.posts.find(:all, :include => :author_favorites) @@ -521,7 +521,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_inheritance - posts = SpecialPost.find(:all, :include => [ :comments ]) + SpecialPost.find(:all, :include => [ :comments ]) end def test_eager_has_one_with_association_inheritance @@ -561,16 +561,16 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_invalid_association_reference assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { - post = Post.find(6, :include=> :monkeys ) + Post.find(6, :include=> :monkeys ) } assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { - post = Post.find(6, :include=>[ :monkeys ]) + Post.find(6, :include=>[ :monkeys ]) } assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { - post = Post.find(6, :include=>[ 'monkeys' ]) + Post.find(6, :include=>[ 'monkeys' ]) } assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") { - post = Post.find(6, :include=>[ :monkeys, :elephants ]) + Post.find(6, :include=>[ :monkeys, :elephants ]) } 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 c55523de38..705550216c 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 @@ -297,7 +297,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_build_by_new_record devel = Developer.new(:name => "Marcel", :salary => 75000) - proj1 = devel.projects.build(:name => "Make bed") + devel.projects.build(:name => "Make bed") proj2 = devel.projects.build(:name => "Lie in it") assert_equal devel.projects.last, proj2 assert !proj2.persisted? @@ -322,7 +322,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_create_by_new_record devel = Developer.new(:name => "Marcel", :salary => 75000) - proj1 = devel.projects.build(:name => "Make bed") + devel.projects.build(:name => "Make bed") proj2 = devel.projects.build(:name => "Lie in it") assert_equal devel.projects.last, proj2 assert !proj2.persisted? @@ -559,8 +559,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_dynamic_find_should_respect_association_order # Developers are ordered 'name DESC, id DESC' - low_id_jamis = developers(:jamis) - middle_id_jamis = developers(:poor_jamis) high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis') assert_equal high_id_jamis, projects(:active_record).developers.find(:first, :conditions => "name = 'Jamis'") diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index e9c119b823..1ddc627940 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -73,7 +73,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [], person.readers assert_nil person.readers.find_by_post_id(post.id) - reader = person.readers.create(:post_id => post.id) + person.readers.create(:post_id => post.id) assert_equal 1, person.readers.count assert_equal 1, person.readers.length @@ -88,7 +88,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [], person.readers assert_nil person.readers.find_by_post_id(post.id) - reader = person.readers.find_or_create_by_post_id(post.id) + person.readers.find_or_create_by_post_id(post.id) assert_equal 1, person.readers.count assert_equal 1, person.readers.length @@ -402,7 +402,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_adding_using_create first_firm = companies(:first_firm) assert_equal 2, first_firm.plain_clients.size - natural = first_firm.plain_clients.create(:name => "Natural Company") + first_firm.plain_clients.create(:name => "Natural Company") assert_equal 3, first_firm.plain_clients.length assert_equal 3, first_firm.plain_clients.size end @@ -483,7 +483,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_build_followed_by_save_does_not_load_target - new_client = companies(:first_firm).clients_of_firm.build("name" => "Another Client") + companies(:first_firm).clients_of_firm.build("name" => "Another Client") assert companies(:first_firm).save assert !companies(:first_firm).clients_of_firm.loaded? end @@ -554,7 +554,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_create_followed_by_save_does_not_load_target - new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client") + companies(:first_firm).clients_of_firm.create("name" => "Another Client") assert companies(:first_firm).save assert !companies(:first_firm).clients_of_firm.loaded? end @@ -852,7 +852,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_dependence_for_associations_with_hash_condition david = authors(:david) - post = posts(:thinking).id assert_difference('Post.count', -1) { assert david.destroy } end @@ -872,7 +871,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_three_levels_of_dependence topic = Topic.create "title" => "neat and simple" reply = topic.replies.create "title" => "neat and simple", "content" => "still digging it" - silly_reply = reply.replies.create "title" => "neat and simple", "content" => "ain't complaining" + reply.replies.create "title" => "neat and simple", "content" => "ain't complaining" assert_nothing_raised { topic.destroy } end @@ -897,7 +896,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_depends_and_nullify num_accounts = Account.count - num_companies = Company.count core = companies(:rails_core) assert_equal accounts(:rails_core_account), core.account @@ -914,7 +912,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_restrict firm = RestrictedFirm.new(:name => 'restrict') firm.save! - child_firm = firm.companies.create(:name => 'child') + firm.companies.create(:name => 'child') assert !firm.companies.empty? assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy } end -- cgit v1.2.3 From 7c5c1a07c03ec03536636c26e09b80b29a59beed Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Sun, 14 Nov 2010 21:54:24 -0500 Subject: if association is already loaded and if a find operation is performed on the already loaded association list with an empty hash then do not perform another sql [#5972 state:resolved] --- .../lib/active_record/associations/association_collection.rb | 3 ++- .../test/cases/associations/has_many_associations_test.rb | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 71d8c2d3c8..5b34ac907c 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -75,6 +75,7 @@ module ActiveRecord find(:first, *args) else load_target unless loaded? + args = args[1..-1] if args.first.kind_of?(Hash) && args.first.empty? @target.first(*args) end end @@ -544,7 +545,7 @@ module ActiveRecord end def fetch_first_or_last_using_find?(args) - args.first.kind_of?(Hash) || !(loaded? || !@owner.persisted? || @reflection.options[:finder_sql] || + (args.first.kind_of?(Hash) && !args.first.empty?) || !(loaded? || !@owner.persisted? || @reflection.options[:finder_sql] || !@target.all? { |record| record.persisted? } || args.first.kind_of?(Integer)) end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 1ddc627940..ecfc769f3a 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -66,6 +66,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 'exotic', bulb.name end + def test_no_sql_should_be_fired_if_association_already_loaded + car = Car.create(:name => 'honda') + bulb = car.bulbs.create + bulbs = Car.first.bulbs + bulbs.inspect # to load all instances of bulbs + assert_no_queries do + bulbs.first() + bulbs.first({}) + end + end + def test_create_resets_cached_counters person = Person.create!(:first_name => 'tenderlove') post = Post.first -- cgit v1.2.3