diff options
47 files changed, 401 insertions, 276 deletions
@@ -10,7 +10,7 @@ gem "rails", :path => File.dirname(__FILE__) gem "rake", ">= 0.8.7" gem "mocha", ">= 0.9.8" -gem "rdoc", ">= 2.5.9" +gem "rdoc", ">= 2.5.10" gem "horo", ">= 1.0.1" # AS @@ -1,4 +1,4 @@ -gem 'rdoc', '>= 2.5.9' +gem 'rdoc', '>= 2.5.10' require 'rdoc' require 'rake' @@ -144,12 +144,6 @@ task :rdoc do FileUtils.copy "activerecord/examples/associations.png", "doc/rdoc/files/examples/associations.png" end -desc "Publish API docs for Rails as a whole and for each component" -task :pdoc => :rdoc do - require 'rake/contrib/sshpublisher' - Rake::SshDirPublisher.new("rails@api.rubyonrails.org", "public_html/api", "doc/rdoc").upload -end - task :update_versions do require File.dirname(__FILE__) + "/version" diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index a47426bd07..cba6e93c8a 100644 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -1,8 +1,5 @@ -gem 'rdoc', '>= 2.5.9' -require 'rdoc' require 'rake' require 'rake/testtask' -require 'rdoc/task' require 'rake/packagetask' require 'rake/gempackagetask' @@ -25,19 +22,6 @@ namespace :test do end end -# Generate the RDoc documentation -RDoc::Task.new { |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = "Action Mailer -- Easy email delivery and testing" - rdoc.options << '--charset' << 'utf-8' - rdoc.options << '-f' << 'horo' - rdoc.options << '--main' << 'README.rdoc' - rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG') - rdoc.rdoc_files.include('lib/action_mailer.rb') - rdoc.rdoc_files.include('lib/action_mailer/*.rb') - rdoc.rdoc_files.include('lib/action_mailer/delivery_method/*.rb') -} - spec = eval(File.read('actionmailer.gemspec')) Rake::GemPackageTask.new(spec) do |p| diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 4af8ea167a..d67c6f2410 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -1,8 +1,5 @@ -gem 'rdoc', '>= 2.5.9' -require 'rdoc' require 'rake' require 'rake/testtask' -require 'rdoc/task' require 'rake/packagetask' require 'rake/gempackagetask' @@ -36,24 +33,6 @@ Rake::TestTask.new(:test_active_record_integration) do |t| t.test_files = Dir.glob("test/activerecord/*_test.rb") end -# Genereate the RDoc documentation - -RDoc::Task.new { |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = "Action Pack -- On rails from request to response" - rdoc.options << '--charset' << 'utf-8' - rdoc.options << '-f' << 'horo' - rdoc.options << '--main' << 'README.rdoc' - if ENV['DOC_FILES'] - rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/)) - else - rdoc.rdoc_files.include('README.rdoc', 'RUNNING_UNIT_TESTS', 'CHANGELOG') - rdoc.rdoc_files.include(Dir['lib/**/*.rb'] - - Dir['lib/*/vendor/**/*.rb']) - rdoc.rdoc_files.exclude('lib/actionpack.rb') - end -} - spec = eval(File.read('actionpack.gemspec')) Rake::GemPackageTask.new(spec) do |p| diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 99deff234c..a5ebc18e2a 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |s| s.add_dependency('i18n', '~> 0.4.1') s.add_dependency('rack', '~> 1.2.1') s.add_dependency('rack-test', '~> 0.5.4') - s.add_dependency('rack-mount', '~> 0.6.9') - s.add_dependency('tzinfo', '~> 0.3.22') + s.add_dependency('rack-mount', '~> 0.6.10') + s.add_dependency('tzinfo', '~> 0.3.23') s.add_dependency('erubis', '~> 2.6.6') end diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index cb644dfd16..aafba2a65f 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -89,6 +89,8 @@ module ActionController #:nodoc: def initialize(controller, resources, options={}) @controller = controller + @request = @controller.request + @format = @controller.formats.first @resource = resources.last @resources = resources @options = options @@ -99,14 +101,6 @@ module ActionController #:nodoc: delegate :head, :render, :redirect_to, :to => :controller delegate :get?, :post?, :put?, :delete?, :to => :request - def request - @request ||= @controller.request - end - - def format - @format ||= @controller.formats.first - end - # Undefine :to_json and :to_yaml since it's defined on Object undef_method(:to_json) if method_defined?(:to_json) undef_method(:to_yaml) if method_defined?(:to_yaml) diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index b64a83c62e..ffb7bdd586 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -6,6 +6,11 @@ module ActionDispatch protocol + host_with_port + fullpath end + # Returns 'https' if this is an SSL request and 'http' otherwise. + def scheme + ssl? ? 'https' : 'http' + end + # Returns 'https://' if this is an SSL request and 'http://' otherwise. def protocol ssl? ? 'https://' : 'http://' @@ -53,6 +58,11 @@ module ActionDispatch end end + # Returns whether this request is using the standard port + def standard_port? + port == standard_port + end + # Returns a \port suffix like ":8080" if the \port number of this request # is not the default HTTP \port 80 or HTTPS \port 443. def port_string diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index c118c72440..800c6b469e 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -288,7 +288,7 @@ module ActionDispatch uri = URI.parse(path_proc.call(*params)) uri.scheme ||= req.scheme uri.host ||= req.host - uri.port ||= req.port unless req.port == 80 + uri.port ||= req.port unless req.standard_port? body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>) @@ -473,7 +473,7 @@ module ActionDispatch def initialize(entities, options = {}) @name = entities.to_s - @path = options.delete(:path) || @name + @path = (options.delete(:path) || @name).to_s @controller = (options.delete(:controller) || @name).to_s @as = options.delete(:as) @options = options @@ -498,16 +498,14 @@ module ActionDispatch end def plural - name.to_s.pluralize + @plural ||= name.to_s end def singular - name.to_s.singularize + @singular ||= name.to_s.singularize end - def member_name - singular - end + alias :member_name :singular # Checks for uncountable plurals, and appends "_index" if they're. def collection_name @@ -518,9 +516,7 @@ module ActionDispatch { :controller => controller } end - def collection_scope - path - end + alias :collection_scope :path def member_scope "#{path}/:id" @@ -541,21 +537,25 @@ module ActionDispatch def initialize(entities, options) @name = entities.to_s - @path = options.delete(:path) || @name + @path = (options.delete(:path) || @name).to_s @controller = (options.delete(:controller) || plural).to_s @as = options.delete(:as) @options = options end - def member_name - name + def plural + @plural ||= name.to_s.pluralize end - alias :collection_name :member_name - def member_scope - path + def singular + @singular ||= name.to_s end - alias :nested_scope :member_scope + + alias :member_name :singular + alias :collection_name :singular + + alias :member_scope :path + alias :nested_scope :path end def initialize(*args) #:nodoc: @@ -586,10 +586,10 @@ module ActionDispatch end if parent_resource.actions.include?(:new) member_scope do + get :edit if parent_resource.actions.include?(:edit) get :show if parent_resource.actions.include?(:show) put :update if parent_resource.actions.include?(:update) delete :destroy if parent_resource.actions.include?(:destroy) - get :edit if parent_resource.actions.include?(:edit) end end @@ -616,10 +616,10 @@ module ActionDispatch end if parent_resource.actions.include?(:new) member_scope do + get :edit if parent_resource.actions.include?(:edit) get :show if parent_resource.actions.include?(:show) put :update if parent_resource.actions.include?(:update) delete :destroy if parent_resource.actions.include?(:destroy) - get :edit if parent_resource.actions.include?(:edit) end end @@ -731,6 +731,7 @@ module ActionDispatch end elsif resource_method_scope? path = path_for_custom_action + options[:action] ||= action options[:as] = name_for_action(options[:as]) if options[:as] args.push(options) @@ -773,6 +774,10 @@ module ActionDispatch return true end + options.each do |k,v| + (options[:constraints] ||= {})[k] = options.delete(k) if options[k].is_a?(Regexp) + end + scope_options = options.slice!(*RESOURCE_OPTIONS) unless scope_options.empty? scope(scope_options) do diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index b9d27be639..43ffadc004 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -538,7 +538,7 @@ module ActionView def extra_tags_for_form(html_options) snowman_tag = tag(:input, :type => "hidden", - :name => "_utf8", :value => "☃".html_safe) + :name => "utf8", :value => "✓".html_safe) method = html_options.delete("method").to_s diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 249fa406a0..546c4cb253 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -132,6 +132,32 @@ class RequestTest < ActiveSupport::TestCase assert_equal [], request.subdomains end + test "standard_port" do + request = stub_request + assert_equal 80, request.standard_port + + request = stub_request 'HTTPS' => 'on' + assert_equal 443, request.standard_port + end + + test "standard_port?" do + request = stub_request + assert !request.ssl? + assert request.standard_port? + + request = stub_request 'HTTPS' => 'on' + assert request.ssl? + assert request.standard_port? + + request = stub_request 'HTTP_HOST' => 'www.example.org:8080' + assert !request.ssl? + assert !request.standard_port? + + request = stub_request 'HTTP_HOST' => 'www.example.org:8443', 'HTTPS' => 'on' + assert request.ssl? + assert !request.standard_port? + end + test "port string" do request = stub_request 'HTTP_HOST' => 'www.example.org:80' assert_equal "", request.port_string @@ -223,6 +249,16 @@ class RequestTest < ActiveSupport::TestCase assert request.ssl? end + test "scheme returns https when proxied" do + request = stub_request 'rack.url_scheme' => 'http' + assert !request.ssl? + assert_equal 'http', request.scheme + + request = stub_request 'rack.url_scheme' => 'http', 'HTTP_X_FORWARDED_PROTO' => 'https' + assert request.ssl? + assert_equal 'https', request.scheme + end + test "String request methods" do [:get, :post, :put, :delete].each do |method| request = stub_request 'REQUEST_METHOD' => method.to_s.upcase diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 3f090b7254..44b83f3afc 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -45,6 +45,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match 'account/logout' => redirect("/logout"), :as => :logout_redirect match 'account/login', :to => redirect("/login") + match 'secure', :to => redirect("/secure/login") constraints(lambda { |req| true }) do match 'account/overview' @@ -128,7 +129,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end member do - get :some_path_with_name + get 'some_path_with_name' put :accessible_projects post :resend, :generate_new_password end @@ -337,6 +338,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resources :content + namespace :transport do + resources :taxis + end + + namespace :medical do + resource :taxis + end + scope :constraints => { :id => /\d+/ } do get '/tickets', :to => 'tickets#index', :as => :tickets end @@ -371,6 +380,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + namespace :wiki do + resources :articles, :id => /[^\/]+/ do + resources :comments, :only => [:create, :new] + end + end + + resources :wiki_pages, :path => :pages + resource :wiki_account, :path => :my_account + scope :only => :show do namespace :only do resources :sectors, :only => :index do @@ -405,6 +423,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + resources :sections, :id => /.+/ do + get :preview, :on => :member + end + match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ end end @@ -1884,11 +1906,126 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_resources_are_not_pluralized + with_test_routes do + get '/transport/taxis' + assert_equal 'transport/taxis#index', @response.body + assert_equal '/transport/taxis', transport_taxis_path + + get '/transport/taxis/new' + assert_equal 'transport/taxis#new', @response.body + assert_equal '/transport/taxis/new', new_transport_taxi_path + + post '/transport/taxis' + assert_equal 'transport/taxis#create', @response.body + + get '/transport/taxis/1' + assert_equal 'transport/taxis#show', @response.body + assert_equal '/transport/taxis/1', transport_taxi_path(:id => '1') + + get '/transport/taxis/1/edit' + assert_equal 'transport/taxis#edit', @response.body + assert_equal '/transport/taxis/1/edit', edit_transport_taxi_path(:id => '1') + + put '/transport/taxis/1' + assert_equal 'transport/taxis#update', @response.body + + delete '/transport/taxis/1' + assert_equal 'transport/taxis#destroy', @response.body + end + end + + def test_singleton_resources_are_not_singularized + with_test_routes do + get '/medical/taxis/new' + assert_equal 'medical/taxes#new', @response.body + assert_equal '/medical/taxis/new', new_medical_taxis_path + + post '/medical/taxis' + assert_equal 'medical/taxes#create', @response.body + + get '/medical/taxis' + assert_equal 'medical/taxes#show', @response.body + assert_equal '/medical/taxis', medical_taxis_path + + get '/medical/taxis/edit' + assert_equal 'medical/taxes#edit', @response.body + assert_equal '/medical/taxis/edit', edit_medical_taxis_path + + put '/medical/taxis' + assert_equal 'medical/taxes#update', @response.body + + delete '/medical/taxis' + assert_equal 'medical/taxes#destroy', @response.body + end + end + + def test_greedy_resource_id_regexp_doesnt_match_edit_and_custom_action + with_test_routes do + get '/sections/1/edit' + assert_equal 'sections#edit', @response.body + assert_equal '/sections/1/edit', edit_section_path(:id => '1') + + get '/sections/1/preview' + assert_equal 'sections#preview', @response.body + assert_equal '/sections/1/preview', preview_section_path(:id => '1') + end + end + + def test_resource_constraints_are_pushed_to_scope + with_test_routes do + get '/wiki/articles/Ruby_on_Rails_3.0' + assert_equal 'wiki/articles#show', @response.body + assert_equal '/wiki/articles/Ruby_on_Rails_3.0', wiki_article_path(:id => 'Ruby_on_Rails_3.0') + + get '/wiki/articles/Ruby_on_Rails_3.0/comments/new' + assert_equal 'wiki/comments#new', @response.body + assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments/new', new_wiki_article_comment_path(:article_id => 'Ruby_on_Rails_3.0') + + post '/wiki/articles/Ruby_on_Rails_3.0/comments' + assert_equal 'wiki/comments#create', @response.body + assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments', wiki_article_comments_path(:article_id => 'Ruby_on_Rails_3.0') + end + end + + def test_resources_path_can_be_a_symbol + with_test_routes do + get '/pages' + assert_equal 'wiki_pages#index', @response.body + assert_equal '/pages', wiki_pages_path + + get '/pages/Ruby_on_Rails' + assert_equal 'wiki_pages#show', @response.body + assert_equal '/pages/Ruby_on_Rails', wiki_page_path(:id => 'Ruby_on_Rails') + + get '/my_account' + assert_equal 'wiki_accounts#show', @response.body + assert_equal '/my_account', wiki_account_path + end + end + + def test_redirect_https + with_test_routes do + with_https do + get '/secure' + verify_redirect 'https://www.example.com/secure/login' + end + end + end + private def with_test_routes yield end + def with_https + old_https = https? + https! + yield + ensure + https!(old_https) + end + def verify_redirect(url, status=301) assert_equal status, @response.status assert_equal url, @response.headers['Location'] diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 4c81e691b2..71a5ae0245 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1513,7 +1513,7 @@ class FormHelperTest < ActionView::TestCase def snowman(method = nil) txt = %{<div style="margin:0;padding:0;display:inline">} - txt << %{<input name="_utf8" type="hidden" value="☃" />} + txt << %{<input name="utf8" type="hidden" value="✓" />} txt << %{<input name="_method" type="hidden" value="#{method}" />} if method txt << %{</div>} end diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index d2f725a994..532f086d21 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -12,7 +12,7 @@ class FormTagHelperTest < ActionView::TestCase method = options[:method] txt = %{<div style="margin:0;padding:0;display:inline">} - txt << %{<input name="_utf8" type="hidden" value="☃" />} + txt << %{<input name="utf8" type="hidden" value="✓" />} txt << %{<input name="_method" type="hidden" value="#{method}" />} if method txt << %{</div>} end diff --git a/activemodel/Rakefile b/activemodel/Rakefile index 3fffc0d021..0372c7a03e 100644 --- a/activemodel/Rakefile +++ b/activemodel/Rakefile @@ -1,8 +1,5 @@ dir = File.dirname(__FILE__) -gem 'rdoc', '>= 2.5.9' -require 'rdoc' - require 'rake/testtask' task :default => :test @@ -22,21 +19,6 @@ namespace :test do end end - -require 'rdoc/task' - -# Generate the RDoc documentation -RDoc::Task.new do |rdoc| - rdoc.rdoc_dir = "doc" - rdoc.title = "Active Model" - rdoc.options << '-f' << 'horo' - rdoc.options << '--charset' << 'utf-8' - rdoc.options << '--main' << 'README.rdoc' - rdoc.rdoc_files.include("README.rdoc", "CHANGELOG") - rdoc.rdoc_files.include("lib/**/*.rb") -end - - require 'rake/packagetask' require 'rake/gempackagetask' diff --git a/activemodel/lib/active_model/validations/callbacks.rb b/activemodel/lib/active_model/validations/callbacks.rb index afd65d3dd5..858cfda73e 100644 --- a/activemodel/lib/active_model/validations/callbacks.rb +++ b/activemodel/lib/active_model/validations/callbacks.rb @@ -40,7 +40,7 @@ module ActiveModel options = args.extract_options! options[:prepend] = true options[:if] = Array.wrap(options[:if]) - options[:if] << "!halted && value != false" + options[:if] << "!halted" options[:if] << "self.validation_context == :#{options[:on]}" if options[:on] set_callback(:validation, :after, *(args << options), &block) end diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index f9fc6613f4..1eed0b0c4d 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -25,9 +25,11 @@ class ValidationsTest < ActiveModel::TestCase r = Reply.new r.title = "There's no content!" assert r.invalid?, "A reply without content shouldn't be saveable" + assert r.after_validation_performed, "after_validation callback should be called" r.content = "Messa content!" assert r.valid?, "A reply with content should be saveable" + assert r.after_validation_performed, "after_validation callback should be called" end def test_single_attr_validation_and_error_msg diff --git a/activemodel/test/models/topic.rb b/activemodel/test/models/topic.rb index f25b774cd7..ff34565bdb 100644 --- a/activemodel/test/models/topic.rb +++ b/activemodel/test/models/topic.rb @@ -1,7 +1,11 @@ class Topic include ActiveModel::Validations + include ActiveModel::Validations::Callbacks attr_accessor :title, :author_name, :content, :approved + attr_accessor :after_validation_performed + + after_validation :perform_after_validation def initialize(attributes = {}) attributes.each do |key, value| @@ -16,4 +20,9 @@ class Topic def condition_is_true_but_its_not false end + + def perform_after_validation + self.after_validation_performed = true + end + end diff --git a/activerecord/Rakefile b/activerecord/Rakefile index c1e90cc099..c2d63cda23 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -1,8 +1,5 @@ -gem 'rdoc', '>= 2.5.9' -require 'rdoc' require 'rake' require 'rake/testtask' -require 'rdoc/task' require 'rake/packagetask' require 'rake/gempackagetask' @@ -163,28 +160,6 @@ end task :build_frontbase_databases => 'frontbase:build_databases' task :rebuild_frontbase_databases => 'frontbase:rebuild_databases' - -# Generate the RDoc documentation - -RDoc::Task.new { |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = "Active Record -- Object-relation mapping put on rails" - rdoc.options << '-f' << 'horo' - rdoc.options << '--main' << 'README.rdoc' - rdoc.options << '--charset' << 'utf-8' - rdoc.rdoc_files.include('README.rdoc', 'RUNNING_UNIT_TESTS', 'CHANGELOG') - rdoc.rdoc_files.include('lib/**/*.rb') - rdoc.rdoc_files.exclude('lib/active_record/vendor/*') - rdoc.rdoc_files.include('dev-utils/*.rb') -} - -# Enhance rdoc task to copy referenced images also -task :rdoc do - FileUtils.mkdir_p "doc/files/examples/" - FileUtils.copy "examples/associations.png", "doc/files/examples/associations.png" -end - - spec = eval(File.read('activerecord.gemspec')) Rake::GemPackageTask.new(spec) do |p| diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index 67d521d56b..a3c0acb370 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -24,5 +24,5 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) s.add_dependency('arel', '~> 0.4.0') - s.add_dependency('tzinfo', '~> 0.3.22') + s.add_dependency('tzinfo', '~> 0.3.23') end diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index b5159eead3..132e9cf882 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -492,7 +492,12 @@ module ActiveRecord def create_record(attrs) attrs.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash) ensure_owner_is_not_new - record = @reflection.klass.send(:with_scope, :create => construct_scope[:create]) do + + _scope = self.construct_scope[:create] + csm = @reflection.klass.send(:current_scoped_methods) + options = (csm.blank? || !_scope.is_a?(Hash)) ? _scope : _scope.merge(csm.where_values_hash) + + record = @reflection.klass.send(:with_scope, :create => options) do @reflection.build_association(attrs) end if block_given? diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 9d3ee9528a..90241dd897 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -918,7 +918,11 @@ module ActiveRecord #:nodoc: self else begin - compute_type(type_name) + if store_full_sti_class + ActiveSupport::Dependencies.constantize(type_name) + else + compute_type(type_name) + end rescue NameError raise SubclassNotFound, "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " + @@ -1171,7 +1175,7 @@ MSG if type_name.match(/^::/) # If the type is prefixed with a scope operator then we assume that # the type_name is an absolute reference. - type_name.constantize + ActiveSupport::Dependencies.constantize(type_name) else # Build a list of candidates to search for candidates = [] @@ -1180,7 +1184,7 @@ MSG candidates.each do |candidate| begin - constant = candidate.constantize + constant = ActiveSupport::Dependencies.constantize(candidate) return constant if candidate == constant.to_s rescue NameError => e # We don't want to swallow NoMethodError < NameError errors diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index c203581735..a31973d529 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -235,7 +235,7 @@ module ActiveRecord :after_initialize, :after_find, :after_touch, :before_validation, :after_validation, :before_save, :around_save, :after_save, :before_create, :around_create, :after_create, :before_update, :around_update, :after_update, - :before_destroy, :around_destroy, :after_destroy + :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback ] included do diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 288ce5aebb..37e584a629 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -93,11 +93,7 @@ module ActiveRecord # #connection can be called any number of times; the connection is # held in a hash keyed by the thread id. def connection - if conn = @reserved_connections[current_connection_id] - conn - else - @reserved_connections[current_connection_id] = checkout - end + @reserved_connections[current_connection_id] ||= checkout end # Signal that the thread is finished with the current connection. @@ -326,7 +322,7 @@ module ActiveRecord # already been opened. def connected?(klass) conn = retrieve_connection_pool(klass) - conn ? conn.connected? : false + conn && conn.connected? end # Remove the connection for this class. This will close the active diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 9950387420..d797f9c6c3 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -31,6 +31,7 @@ module ActiveRecord mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslca] || config[:sslkey] default_flags = Mysql.const_defined?(:CLIENT_MULTI_RESULTS) ? Mysql::CLIENT_MULTI_RESULTS : 0 + default_flags |= Mysql::CLIENT_FOUND_ROWS if Mysql.const_defined?(:CLIENT_FOUND_ROWS) options = [host, username, password, database, port, socket, default_flags] ConnectionAdapters::MysqlAdapter.new(mysql, logger, options, config) end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index cfe4d23965..03b06205d4 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -316,16 +316,19 @@ module ActiveRecord @to_sql ||= arel.to_sql end - def scope_for_create - @scope_for_create ||= begin - @create_with_value || Hash[ - @where_values.find_all { |w| + def where_values_hash + Hash[@where_values.find_all { |w| w.respond_to?(:operator) && w.operator == :== }.map { |where| [where.operand1.name, where.operand2.respond_to?(:value) ? where.operand2.value : where.operand2] }] + end + + def scope_for_create + @scope_for_create ||= begin + @create_with_value || where_values_hash end end diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 64edcc1ef3..7cf73f7eb3 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -163,19 +163,17 @@ module ActiveRecord def perform_calculation(operation, column_name, options = {}) operation = operation.to_s.downcase + distinct = nil + if operation == "count" column_name ||= (select_for_count || :all) - joins = arel.joins(arel) - if joins.present? && joins =~ /LEFT OUTER/i + if arel.joins(arel) =~ /LEFT OUTER/i distinct = true column_name = @klass.primary_key if column_name == :all end - distinct = nil if column_name.to_s =~ /\s*DISTINCT\s+/i - distinct ||= options[:distinct] - else - distinct = nil + distinct = nil if column_name =~ /\s*DISTINCT\s+/i end distinct = options[:distinct] || distinct diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 0bf0b37900..0b5e9b4fb2 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -229,7 +229,7 @@ module ActiveRecord arel.project(selects.last) end else - arel.project(@klass.quoted_table_name + '.*') + arel.project(Arel::SqlLiteral.new(@klass.quoted_table_name + '.*')) end end diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index b973da621b..26091c713b 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -27,7 +27,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase sleep 2 @connection.verify! assert @connection.active? - end + end private diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index e9240de673..efaab8569e 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -46,16 +46,13 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent end + def test_extension_name + extension = Proc.new {} + name = :association_name - def test_extension_name - extension = Proc.new {} - name = :association_name - - assert_equal 'DeveloperAssociationNameAssociationExtension', Developer.send(:create_extension_modules, name, extension, []).first.name - assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name + assert_equal 'DeveloperAssociationNameAssociationExtension', Developer.send(:create_extension_modules, name, extension, []).first.name + assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name end - - end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 7e10a8ceeb..63fc15bca3 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -13,6 +13,8 @@ require 'models/reader' require 'models/tagging' require 'models/invoice' require 'models/line_item' +require 'models/car' +require 'models/bulb' class HasManyAssociationsTestForCountWithFinderSql < ActiveRecord::TestCase class Invoice < ActiveRecord::Base @@ -47,6 +49,23 @@ class HasManyAssociationsTest < ActiveRecord::TestCase Client.destroyed_client_ids.clear end + def test_create_from_association_should_respect_default_scope + car = Car.create(:name => 'honda') + assert_equal 'honda', car.name + + bulb = Bulb.create + assert_equal 'defaulty', bulb.name + + bulb = car.bulbs.build + assert_equal 'defaulty', bulb.name + + bulb = car.bulbs.create + assert_equal 'defaulty', bulb.name + + bulb = car.bulbs.create(:name => 'exotic') + assert_equal 'exotic', bulb.name + end + def test_create_resets_cached_counters person = Person.create!(:first_name => 'tenderlove') post = Post.first diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 4693cb45fc..52382f5afc 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -249,8 +249,8 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test assert_equal customer1, order.billing assert_equal customer2, order.shipping - assert_equal num_orders +1, Order.count - assert_equal num_customers +2, Customer.count + assert_equal num_orders + 1, Order.count + assert_equal num_customers + 2, Customer.count end def test_store_association_in_two_relations_with_one_save @@ -268,8 +268,8 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test assert_equal customer, order.billing assert_equal customer, order.shipping - assert_equal num_orders +1, Order.count - assert_equal num_customers +1, Customer.count + assert_equal num_orders + 1, Order.count + assert_equal num_customers + 1, Customer.count end def test_store_association_in_two_relations_with_one_save_in_existing_object @@ -287,8 +287,8 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test assert_equal customer, order.billing assert_equal customer, order.shipping - assert_equal num_orders +1, Order.count - assert_equal num_customers +1, Customer.count + assert_equal num_orders + 1, Order.count + assert_equal num_customers + 1, Customer.count end def test_store_association_in_two_relations_with_one_save_in_existing_object_with_values @@ -311,14 +311,14 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test assert_equal customer, order.billing assert_equal customer, order.shipping - assert_equal num_orders +1, Order.count - assert_equal num_customers +2, Customer.count + assert_equal num_orders + 1, Order.count + assert_equal num_customers + 2, Customer.count end def test_store_association_with_a_polymorphic_relationship num_tagging = Tagging.count tags(:misc).create_tagging(:taggable => posts(:thinking)) - assert_equal num_tagging +1, Tagging.count + assert_equal num_tagging + 1, Tagging.count end end @@ -372,7 +372,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert firm.save assert !client.new_record? - assert_equal no_of_clients+1, Client.count + assert_equal no_of_clients + 1, Client.count end def test_invalid_build @@ -403,8 +403,8 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert !new_firm.new_record? assert !c.new_record? 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. + 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. assert_equal 2, new_firm.clients_of_firm.size assert_equal 2, new_firm.clients_of_firm(true).size @@ -1061,7 +1061,7 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_allow_to_bypass_validations_on_the_associated_models_on_create - assert_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count", +2) do + assert_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count", 2) do 2.times { @pirate.send(@association_name).build } @pirate.save(:validate => false) end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index b2799f649a..55f0b1ce21 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1409,7 +1409,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_compute_type_no_method_error - String.any_instance.stubs(:constantize).raises(NoMethodError) + ActiveSupport::Dependencies.stubs(:constantize).raises(NoMethodError) assert_raises NoMethodError do ActiveRecord::Base.send :compute_type, 'InvalidModel' end diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index dc7f82b001..8a84f19836 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -461,7 +461,12 @@ class CallbacksTest < ActiveRecord::TestCase [ :before_validation, :proc ], [ :before_validation, :object ], [ :before_validation, :block ], - [ :before_validation, :returning_false ] + [ :before_validation, :returning_false ], + [ :after_rollback, :block ], + [ :after_rollback, :object ], + [ :after_rollback, :proc ], + [ :after_rollback, :string ], + [ :after_rollback, :method ], ], david.history end diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb index e61960059e..de5fa140ba 100644 --- a/activerecord/test/cases/pooled_connections_test.rb +++ b/activerecord/test/cases/pooled_connections_test.rb @@ -89,7 +89,7 @@ class PooledConnectionsTest < ActiveRecord::TestCase def test_undefined_connection_returns_false old_handler = ActiveRecord::Base.connection_handler ActiveRecord::Base.connection_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new - assert_equal false, ActiveRecord::Base.connected? + assert ! ActiveRecord::Base.connected? ensure ActiveRecord::Base.connection_handler = old_handler end diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index cc146f5574..85f222bca2 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -260,22 +260,26 @@ class TransactionObserverCallbacksTest < ActiveRecord::TestCase class TopicWithObserverAttachedObserver < ActiveRecord::Observer def after_commit(record) - record.history.push :"TopicWithObserverAttachedObserver#after_commit" + record.history.push "after_commit" end def after_rollback(record) - record.history.push :"TopicWithObserverAttachedObserver#after_rollback" + record.history.push "after_rollback" end end def test_after_commit_called + assert TopicWithObserverAttachedObserver.instance, 'should have observer' + topic = TopicWithObserverAttached.new topic.save! - assert_equal topic.history, [:"TopicWithObserverAttachedObserver#after_commit"] + assert_equal %w{ after_commit }, topic.history end def test_after_rollback_called + assert TopicWithObserverAttachedObserver.instance, 'should have observer' + topic = TopicWithObserverAttached.new Topic.transaction do @@ -283,6 +287,6 @@ class TransactionObserverCallbacksTest < ActiveRecord::TestCase raise ActiveRecord::Rollback end - assert_equal topic.history, [:"TopicWithObserverObserver#after_rollback"] + assert_equal %w{ after_rollback }, topic.history end end diff --git a/activerecord/test/models/bulb.rb b/activerecord/test/models/bulb.rb new file mode 100644 index 0000000000..9eefc5803a --- /dev/null +++ b/activerecord/test/models/bulb.rb @@ -0,0 +1,7 @@ +class Bulb < ActiveRecord::Base + + default_scope :conditions => {:name => 'defaulty' } + + belongs_to :car + +end diff --git a/activerecord/test/models/car.rb b/activerecord/test/models/car.rb index faf4e6cbc0..903ec53288 100644 --- a/activerecord/test/models/car.rb +++ b/activerecord/test/models/car.rb @@ -1,4 +1,5 @@ class Car < ActiveRecord::Base + has_many :bulbs has_many :tyres has_many :engines has_many :wheels, :as => :wheelable diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 8017e13920..7657e00800 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -198,6 +198,11 @@ ActiveRecord::Schema.define do t.integer :car_id end + create_table :bulbs, :force => true do |t| + t.integer :car_id + t.string :name + end + create_table :entrants, :force => true do |t| t.string :name, :null => false t.integer :course_id, :null => false diff --git a/activeresource/Rakefile b/activeresource/Rakefile index 2145f1017c..905241acc0 100644 --- a/activeresource/Rakefile +++ b/activeresource/Rakefile @@ -1,8 +1,5 @@ -gem 'rdoc', '>= 2.5.9' -require 'rdoc' require 'rake' require 'rake/testtask' -require 'rdoc/task' require 'rake/packagetask' require 'rake/gempackagetask' @@ -27,20 +24,6 @@ namespace :test do end end -# Generate the RDoc documentation - -RDoc::Task.new { |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = "Active Resource -- Object-oriented REST services" - rdoc.options << '-f' << 'horo' - rdoc.options << '--main' << 'README.rdoc' - rdoc.options << '--charset' << 'utf-8' - rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG') - rdoc.rdoc_files.include('lib/**/*.rb') - rdoc.rdoc_files.exclude('lib/activeresource.rb') -} - - spec = eval(File.read('activeresource.gemspec')) Rake::GemPackageTask.new(spec) do |p| diff --git a/activesupport/Rakefile b/activesupport/Rakefile index 8e2683ef89..d117ca6356 100644 --- a/activesupport/Rakefile +++ b/activesupport/Rakefile @@ -1,7 +1,4 @@ -gem 'rdoc', '>= 2.5.9' -require 'rdoc' require 'rake/testtask' -require 'rdoc/task' require 'rake/gempackagetask' task :default => :test @@ -9,6 +6,7 @@ Rake::TestTask.new do |t| t.libs << 'test' t.pattern = 'test/**/*_test.rb' t.warning = true + t.verbose = true end namespace :test do @@ -20,19 +18,6 @@ end # Create compressed packages dist_dirs = [ "lib", "test"] -# Genereate the RDoc documentation - -RDoc::Task.new { |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = "Active Support -- Utility classes and standard library extensions from Rails" - rdoc.options << '-f' << 'horo' - rdoc.options << '--main' << 'README.rdoc' - rdoc.options << '--charset' << 'utf-8' - rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG') - rdoc.rdoc_files.include('lib/active_support.rb') - rdoc.rdoc_files.include('lib/active_support/**/*.rb') -} - spec = eval(File.read('activesupport.gemspec')) Rake::GemPackageTask.new(spec) do |p| diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb index 0420e206af..aad4b61e16 100644 --- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb +++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb @@ -7,8 +7,6 @@ class Hash # {:a => 1}.with_indifferent_access["a"] # => 1 # def with_indifferent_access - hash = ActiveSupport::HashWithIndifferentAccess.new(self) - hash.default = self.default - hash + ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self) end end diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 2b80bd214f..e6170b2daf 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -63,58 +63,78 @@ module ActiveSupport #:nodoc: mattr_accessor :log_activity self.log_activity = false - class WatchStack < Array + # The WatchStack keeps a stack of the modules being watched as files are loaded. + # If a file in the process of being loaded (parent.rb) triggers the load of + # another file (child.rb) the stack will ensure that child.rb handles the new + # constants. + # + # If child.rb is being autoloaded, its constants will be added to + # autoloaded_constants. If it was being `require`d, they will be discarded. + # + # This is handled by walking back up the watch stack and adding the constants + # found by child.rb to the list of original constants in parent.rb + class WatchStack < Hash + # @watching is a stack of lists of constants being watched. For instance, + # if parent.rb is autoloaded, the stack will look like [[Object]]. If parent.rb + # then requires namespace/child.rb, the stack will look like [[Object], [Namespace]]. + def initialize - @mutex = Mutex.new + @watching = [] + super { |h,k| h[k] = [] } end - def self.locked(*methods) - methods.each { |m| class_eval "def #{m}(*) lock { super } end", __FILE__, __LINE__ } - end + # return a list of new constants found since the last call to watch_modules + def new_constants + constants = [] - locked :concat, :each, :delete_if, :<< + # Grab the list of namespaces that we're looking for new constants under + @watching.last.each do |namespace| + # Retrieve the constants that were present under the namespace when watch_modules + # was originally called + original_constants = self[namespace].last - def new_constants_for(frames) - constants = [] - frames.each do |mod_name, prior_constants| - mod = Inflector.constantize(mod_name) if Dependencies.qualified_const_defined?(mod_name) + mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace) next unless mod.is_a?(Module) - new_constants = mod.local_constant_names - prior_constants - - # If we are checking for constants under, say, :Object, nested under something - # else that is checking for constants also under :Object, make sure the - # parent knows that we have found, and taken care of, the constant. - # - # In particular, this means that since Kernel.require discards the constants - # it finds, parents will be notified that about those constants, and not - # consider them "new". As a result, they will not be added to the - # autoloaded_constants list. - each do |key, value| - value.concat(new_constants) if key == mod_name + # Get a list of the constants that were added + new_constants = mod.local_constant_names - original_constants + + # self[namespace] returns an Array of the constants that are being evaluated + # for that namespace. For instance, if parent.rb requires child.rb, the first + # element of self[Object] will be an Array of the constants that were present + # before parent.rb was required. The second element will be an Array of the + # constants that were present before child.rb was required. + self[namespace].each do |namespace_constants| + namespace_constants.concat(new_constants) end + # Normalize the list of new constants, and add them to the list we will return new_constants.each do |suffix| - constants << ([mod_name, suffix] - ["Object"]).join("::") + constants << ([namespace, suffix] - ["Object"]).join("::") end end constants + ensure + # A call to new_constants is always called after a call to watch_modules + pop_modules(@watching.pop) end # Add a set of modules to the watch stack, remembering the initial constants - def add_modules(modules) - list = modules.map do |desc| - name = Dependencies.to_constant_name(desc) - consts = Dependencies.qualified_const_defined?(name) ? - Inflector.constantize(name).local_constant_names : [] - [name, consts] + def watch_namespaces(namespaces) + watching = [] + namespaces.map do |namespace| + module_name = Dependencies.to_constant_name(namespace) + original_constants = Dependencies.qualified_const_defined?(module_name) ? + Inflector.constantize(module_name).local_constant_names : [] + + watching << module_name + self[module_name] << original_constants end - concat(list) - list + @watching << watching end - def lock - @mutex.synchronize { yield self } + def pop_modules(modules) + modules.each { |mod| self[mod].pop } end end @@ -563,14 +583,15 @@ module ActiveSupport #:nodoc: # and will be removed immediately. def new_constants_in(*descs) log_call(*descs) - watch_frames = constant_watch_stack.add_modules(descs) + constant_watch_stack.watch_namespaces(descs) aborting = true + begin yield # Now yield to the code that is to define new constants. aborting = false ensure - new_constants = constant_watch_stack.new_constants_for(watch_frames) + new_constants = constant_watch_stack.new_constants log "New constants: #{new_constants * ', '}" return new_constants unless aborting @@ -580,9 +601,6 @@ module ActiveSupport #:nodoc: end return [] - ensure - # Remove the stack frames that we added. - watch_frames.each {|f| constant_watch_stack.delete(f) } if watch_frames.present? end class LoadingModule #:nodoc: diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index eec5d4cf47..e8215bc566 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -1,4 +1,3 @@ -require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/hash/keys' # This class has dubious semantics and we only have it so that @@ -28,6 +27,12 @@ module ActiveSupport end end + def self.new_from_hash_copying_default(hash) + ActiveSupport::HashWithIndifferentAccess.new(hash).tap do |new_hash| + new_hash.default = hash.default + end + end + alias_method :regular_writer, :[]= unless method_defined?(:regular_writer) alias_method :regular_update, :update unless method_defined?(:regular_update) @@ -102,7 +107,7 @@ module ActiveSupport # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess. def reverse_merge(other_hash) - super other_hash.with_indifferent_access + super self.class.new_from_hash_copying_default(other_hash) end def reverse_merge!(other_hash) @@ -133,9 +138,9 @@ module ActiveSupport def convert_value(value) case value when Hash - value.with_indifferent_access + self.class.new_from_hash_copying_default(value) when Array - value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e } + value.collect { |e| e.is_a?(Hash) ? self.class.new_from_hash_copying_default(e) : e } else value end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index f98d823f00..77b885dc3d 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -576,14 +576,14 @@ class DependenciesTest < Test::Unit::TestCase def test_new_contants_in_without_constants assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { }) - assert ActiveSupport::Dependencies.constant_watch_stack.empty? + assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } end def test_new_constants_in_with_a_single_constant assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) { Object.const_set :Hello, 10 }.map(&:to_s) - assert ActiveSupport::Dependencies.constant_watch_stack.empty? + assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } ensure Object.class_eval { remove_const :Hello } end @@ -600,7 +600,7 @@ class DependenciesTest < Test::Unit::TestCase end assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s) - assert ActiveSupport::Dependencies.constant_watch_stack.empty? + assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } ensure %w(OuterBefore Inner OuterAfter).each do |name| Object.class_eval { remove_const name if const_defined?(name) } @@ -621,7 +621,7 @@ class DependenciesTest < Test::Unit::TestCase M.const_set :OuterAfter, 30 end assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort - assert ActiveSupport::Dependencies.constant_watch_stack.empty? + assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } ensure Object.class_eval { remove_const :M } end @@ -639,7 +639,7 @@ class DependenciesTest < Test::Unit::TestCase M.const_set :OuterAfter, 30 end assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort - assert ActiveSupport::Dependencies.constant_watch_stack.empty? + assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } ensure Object.class_eval { remove_const :M } end diff --git a/ci/ci_build.rb b/ci/ci_build.rb index e75f91cd3b..3591e45fcf 100755 --- a/ci/ci_build.rb +++ b/ci/ci_build.rb @@ -27,7 +27,7 @@ cd root_dir do puts puts "[CruiseControl] Bundling RubyGems" puts - build_results[:bundle] = system 'rm -rf ~/.bundle; env CI=1 bundle update' + build_results[:bundle] = system 'bundle update' end cd "#{root_dir}/activesupport" do diff --git a/railties/Rakefile b/railties/Rakefile index 8e78d2ff4a..9ef6637c1e 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -1,8 +1,5 @@ -gem 'rdoc', '>= 2.5.9' -require 'rdoc' require 'rake' require 'rake/testtask' -require 'rdoc/task' require 'rake/gempackagetask' require 'date' @@ -58,19 +55,6 @@ task :validate_guides do ruby "guides/w3c_validator.rb" end -# Generate documentation ------------------------------------------------------------------ - -RDoc::Task.new { |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = "Railties -- Gluing the Engine to the Rails" - rdoc.options << '-f' << 'horo' - rdoc.options << '--main' << 'README.rdoc' - rdoc.options << '--charset' << 'utf-8' - rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG') - rdoc.rdoc_files.include('lib/**/*.rb') - rdoc.rdoc_files.exclude('lib/rails/generators/**/templates/*') -} - # Generate GEM ---------------------------------------------------------------------------- spec = eval(File.read('railties.gemspec')) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 4e257d2e00..0a2f60c30a 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -150,7 +150,7 @@ Here the only two gems we need are +rails+ and +sqlite3-ruby+, so it seems. This * nokogiri-1.4.3.1.gem * polyglot-0.3.1.gem * rack-1.2.1.gem -* rack-mount-0.6.9.gem +* rack-mount-0.6.10.gem * rack-test-0.5.4.gem * rails-3.0.0.beta4.gem * railties-3.0.0.beta4.gem @@ -160,7 +160,7 @@ Here the only two gems we need are +rails+ and +sqlite3-ruby+, so it seems. This * text-hyphen-1.0.0.gem * thor-0.13.7.gem * treetop-1.4.8.gem -* tzinfo-0.3.22.gem +* tzinfo-0.3.23.gem TODO: Prettify when it becomes more stable. |