diff --git a/Gemfile b/Gemfile index 81b7ce4d4914ac4cc886e6eda07cfcf7aed09210..68e6487e2c0e11443dcc54d267a83e7c94a99cfd 100644 --- a/Gemfile +++ b/Gemfile @@ -1,17 +1,20 @@ -gem "rake", ">= 0.8.7" +path File.expand_path('..', __FILE__) +source :gemcutter + +gem "rails", "3.0.pre" + +gem "rake", ">= 0.8.7" gem "mocha", ">= 0.9.8" -gem "ruby-debug", ">= 0.10.3" if RUBY_VERSION < '1.9' -gem "rails", "3.0.pre", :path => "railties" -%w(activesupport activemodel actionpack actionmailer activerecord activeresource).each do |lib| - gem lib, '3.0.pre', :path => lib +if RUBY_VERSION < '1.9' + gem "ruby-debug", ">= 0.10.3" end # AR -gem "arel", "0.2.pre", :git => "git://github.com/rails/arel.git" +gem "arel", ">= 0.2.0" gem "sqlite3-ruby", ">= 1.2.5" -only :test do +group :test do gem "pg", ">= 0.8.0" gem "mysql", ">= 2.8.1" end @@ -21,8 +24,6 @@ gem "rack-test", "0.5.3" gem "RedCloth", ">= 4.2.2" if ENV['CI'] - disable_system_gems - gem "nokogiri", ">= 1.4.0" gem "memcache-client", ">= 1.7.6" @@ -34,5 +35,3 @@ if ENV['CI'] gem "test-unit", ">= 2.0.5" end end - -disable_system_gems diff --git a/Rakefile b/Rakefile index 5ae09160f0109247d9465fc4fb32db6b42b9e3e6..a102b38cb7392276d438bb97ff61ae6749762ea3 100644 --- a/Rakefile +++ b/Rakefile @@ -38,7 +38,6 @@ Rake::GemPackageTask.new(spec) do |pkg| end task :install => :gem do - system %(cd arel && gem build arel.gemspec && gem install arel-0.2.pre.gem --no-ri --no-rdoc --ignore-dependencies) system %(cd rack && rake gem VERSION=1.0.2.pre && gem install rack-1.0.2.pre.gem --no-ri --no-rdoc --ignore-dependencies) (PROJECTS - ["railties"]).each do |project| puts "INSTALLING #{project}" diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index aa9822c6ab6d4d62cee95843aa37df55ed420670..ec85a20f70bbee064ab6322f7bca05ce1984eb75 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -268,13 +268,13 @@ class Base < AbstractController::Base private_class_method :new #:nodoc: - extlib_inheritable_accessor :default_params + class_attribute :default_params self.default_params = { :mime_version => "1.0", :charset => "utf-8", :content_type => "text/plain", :parts_order => [ "text/plain", "text/enriched", "text/html" ] - } + }.freeze class << self @@ -284,9 +284,9 @@ def mailer_name attr_writer :mailer_name alias :controller_path :mailer_name - def default(value=nil) - self.default_params.merge!(value) if value - self.default_params + def default(value = nil) + self.default_params = default_params.merge(value).freeze if value + default_params end # Receives a raw email, parses it into an email object, decodes it, diff --git a/actionmailer/lib/action_mailer/delivery_methods.rb b/actionmailer/lib/action_mailer/delivery_methods.rb index 7e92aea8fd0ce27d7abbe73a0e0380a1bd07dd3f..043794bb12daf5395faf37c9bec63c3d29f9e197 100644 --- a/actionmailer/lib/action_mailer/delivery_methods.rb +++ b/actionmailer/lib/action_mailer/delivery_methods.rb @@ -7,8 +7,7 @@ module DeliveryMethods extend ActiveSupport::Concern included do - extlib_inheritable_accessor :delivery_methods, :delivery_method, - :instance_writer => false + class_attribute :delivery_methods, :delivery_method # Do not make this inheritable, because we always want it to propagate cattr_accessor :raise_delivery_errors @@ -17,7 +16,7 @@ module DeliveryMethods cattr_accessor :perform_deliveries self.perform_deliveries = true - self.delivery_methods = {} + self.delivery_methods = {}.freeze self.delivery_method = :smtp add_delivery_method :smtp, Mail::SMTP, @@ -53,12 +52,9 @@ module ClassMethods # :arguments => '-i -t' # def add_delivery_method(symbol, klass, default_options={}) - unless respond_to?(:"#{symbol}_settings") - extlib_inheritable_accessor(:"#{symbol}_settings", :instance_writer => false) - end - + class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings") send(:"#{symbol}_settings=", default_options) - self.delivery_methods[symbol.to_sym] = klass + self.delivery_methods = delivery_methods.merge(symbol.to_sym => klass).freeze end def wrap_delivery_behavior(mail, method=nil) #:nodoc: @@ -87,4 +83,4 @@ def wrap_delivery_behavior!(*args) #:nodoc: self.class.wrap_delivery_behavior(message, *args) end end -end \ No newline at end of file +end diff --git a/actionmailer/lib/action_mailer/deprecated_api.rb b/actionmailer/lib/action_mailer/deprecated_api.rb index 54ad18f796f44f579eaf10c88347c184022e577b..c08ab4164e6444763bbb4858eedfcb6e50f51abb 100644 --- a/actionmailer/lib/action_mailer/deprecated_api.rb +++ b/actionmailer/lib/action_mailer/deprecated_api.rb @@ -47,7 +47,7 @@ def template_root end def template_root=(root) - ActiveSupport::Deprecation.warn "template_root= is deprecated, use view_paths.unshift instead", caller[0,2] + ActiveSupport::Deprecation.warn "template_root= is deprecated, use prepend_view_path instead", caller[0,2] self.view_paths = ActionView::Base.process_view_paths(root) end diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index ce09bb5d61254da318200a24cdefb3594015c637..f6baa4a9e878347acd30faaafdeb74d355736460 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -1,14 +1,8 @@ -begin - require File.expand_path('../../../vendor/gems/environment', __FILE__) -rescue LoadError -end - -lib = File.expand_path('../../lib', __FILE__) -$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) +require File.expand_path('../../../load_paths', __FILE__) -require 'rubygems' require 'test/unit' require 'action_mailer' +require 'action_mailer/test_case' # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index 57bfe2375e62512aaa1bb4cec91cead32f25e558..7e794e10e8e35ba8bbc77287d2ba2a5ece8b9faa 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -81,8 +81,8 @@ def custom_block(include_html=false) def different_template(template_name='') mail do |format| - format.text { render :template => template_name } - format.html { render :template => template_name } + format.text { render :template => "#{mailer_name}/#{template_name}" } + format.html { render :template => "#{mailer_name}/#{template_name}" } end end @@ -254,7 +254,7 @@ def different_layout(layout_name='') end test "subject gets default from I18n" do - BaseMailer.default[:subject] = nil + BaseMailer.default :subject => nil email = BaseMailer.welcome(:subject => nil) assert_equal "Welcome", email.subject @@ -331,22 +331,24 @@ def different_layout(layout_name='') end test "implicit multipart with several view paths uses the first one with template" do + old = BaseMailer.view_paths begin - BaseMailer.view_paths.unshift(File.join(FIXTURE_LOAD_PATH, "another.path")) + BaseMailer.view_paths = [File.join(FIXTURE_LOAD_PATH, "another.path")] + old.dup email = BaseMailer.welcome assert_equal("Welcome from another path", email.body.encoded) ensure - BaseMailer.view_paths.shift + BaseMailer.view_paths = old end end test "implicit multipart with inexistent templates uses the next view path" do + old = BaseMailer.view_paths begin - BaseMailer.view_paths.unshift(File.join(FIXTURE_LOAD_PATH, "unknown")) + BaseMailer.view_paths = [File.join(FIXTURE_LOAD_PATH, "unknown")] + old.dup email = BaseMailer.welcome assert_equal("Welcome", email.body.encoded) ensure - BaseMailer.view_paths.shift + BaseMailer.view_paths = old end end @@ -503,16 +505,10 @@ def swap(klass, new_values) end def with_default(klass, new_values) - hash = klass.default - old_values = {} - new_values.each do |key, value| - old_values[key] = hash[key] - hash[key] = value - end + old = klass.default_params + klass.default(new_values) yield ensure - old_values.each do |key, value| - hash[key] = value - end + klass.default_params = old end end diff --git a/actionmailer/test/delivery_methods_test.rb b/actionmailer/test/delivery_methods_test.rb index 4907ca09035efd1dbb2539638f5d0e0758342fd3..22a7d19bc25bff1b49efb5a4a22822e8c4d8db14 100644 --- a/actionmailer/test/delivery_methods_test.rb +++ b/actionmailer/test/delivery_methods_test.rb @@ -45,7 +45,9 @@ def setup def teardown ActionMailer::Base.delivery_method = @old_delivery_method - ActionMailer::Base.delivery_methods.delete(:custom) + new = ActionMailer::Base.delivery_methods.dup + new.delete(:custom) + ActionMailer::Base.delivery_methods = new end test "allow to add custom delivery method" do @@ -167,4 +169,4 @@ def teardown assert_equal(0, DeliveryMailer.deliveries.length) end -end \ No newline at end of file +end diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index eb621c08651f38763902da1c42f69c81e318c7c9..578b884a4d535bb130bc1329173ff326740f48a1 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -1,4 +1,6 @@ require 'active_support/dependencies' +require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/module/delegation' module AbstractController module Helpers @@ -12,10 +14,10 @@ def self.next_serial end included do - extlib_inheritable_accessor(:_helpers) { Module.new } - extlib_inheritable_accessor(:_helper_serial) do - AbstractController::Helpers.next_serial - end + class_attribute :_helpers, :_helper_serial + delegate :_helpers, :to => :'self.class' + self._helpers = Module.new + self._helper_serial = ::AbstractController::Helpers.next_serial end module ClassMethods diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 56ddf9bf01a196ee9cf93307efd4942df2e3232e..0d214396aaf1f453b17f87942c9d5319743a85a5 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -1,3 +1,6 @@ +require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/module/delegation' + module AbstractController # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in # repeated setups. The inclusion pattern has pages that look like this: @@ -161,8 +164,9 @@ module Layouts include Rendering included do - extlib_inheritable_accessor(:_layout_conditions) { Hash.new } - extlib_inheritable_accessor(:_action_has_layout) { Hash.new } + class_attribute :_layout_conditions + delegate :_layout_conditions, :to => :'self.class' + self._layout_conditions = {} _write_layout_method end diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index ac407bda5e84538fd17d67c737b3f3eacc6db91a..619a49571bcdd6585ec741a16118c1eb827a02f0 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -1,4 +1,7 @@ require "abstract_controller/base" +require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/array/wrap' module AbstractController class DoubleRenderError < Error @@ -13,8 +16,9 @@ module Rendering extend ActiveSupport::Concern included do - extlib_inheritable_accessor :_view_paths - self._view_paths ||= ActionView::PathSet.new + class_attribute :_view_paths + delegate :_view_paths, :to => :'self.class' + self._view_paths = ActionView::PathSet.new end # An instance of a view class. The default view class is ActionView::Base @@ -156,7 +160,6 @@ def _determine_template(options) elsif options.key?(:file) options[:_template_name] = options[:file] end - name = (options[:_template_name] || options[:action] || action_name).to_s options[:_prefix] ||= _prefix if (options.keys & [:partial, :file, :template]).empty? @@ -201,7 +204,7 @@ def clear_template_caches! # the default view path. You may also provide a custom view path # (see ActionView::ViewPathSet for more information) def append_view_path(path) - self.view_paths << path + self.view_paths = view_paths.dup + Array.wrap(path) end # Prepend a path to the list of view paths for this controller. @@ -212,12 +215,12 @@ def append_view_path(path) # (see ActionView::ViewPathSet for more information) def prepend_view_path(path) clear_template_caches! - self.view_paths.unshift(path) + self.view_paths = Array.wrap(path) + view_paths.dup end # A list of all of the default view paths for this controller. def view_paths - self._view_paths + _view_paths end # Set the view paths. @@ -228,7 +231,8 @@ def view_paths def view_paths=(paths) clear_template_caches! self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths) + _view_paths.freeze end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 57627a6f0b8e9abe0474d4150352ce981d6f3880..2b35e111ec75f04a7313d5c315da7c838b1f5272 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/class/attribute' module ActionController # ActionController::Metal provides a way to get a valid Rack application from a controller. @@ -90,7 +90,12 @@ def call(env) end end - extlib_inheritable_accessor(:middleware_stack) { ActionDispatch::MiddlewareStack.new } + class_attribute :middleware_stack + self.middleware_stack = ActionDispatch::MiddlewareStack.new + + def self.inherited(base) + self.middleware_stack = base.middleware_stack.dup + end def self.use(*args) middleware_stack.use(*args) diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb index 2be0fa097e35a9b37b8f4a1f2eb6af818b4f0dd0..1d4a719aa6d73a3727bc0fb017fbb74bf78e67e0 100644 --- a/actionpack/lib/action_controller/metal/compatibility.rb +++ b/actionpack/lib/action_controller/metal/compatibility.rb @@ -15,9 +15,6 @@ class ::ActionController::ActionControllerError < StandardError #:nodoc: cattr_accessor :session_options self.session_options = {} - cattr_accessor :allow_concurrency - self.allow_concurrency = false - cattr_accessor :relative_url_root self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT'] @@ -44,9 +41,6 @@ class << self self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : "" - cattr_accessor :consider_all_requests_local - self.consider_all_requests_local = true - # Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets, # and images to a dedicated asset server away from the main web server. Example: # ActionController::Base.asset_host = "http://assets.example.com" @@ -74,6 +68,25 @@ def process_action(*) module ClassMethods def consider_all_requests_local + ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local is deprecated, " << + "use Rails.application.config.consider_all_requests_local instead" + Rails.application.config.consider_all_requests_local + end + + def consider_all_requests_local=(value) + ActiveSupport::Deprecation.warn "ActionController::Base.consider_all_requests_local= is no longer effective. " << + "Please configure it on your application with config.consider_all_requests_local=" + end + + def allow_concurrency + ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency is deprecated, " << + "use Rails.application.config.allow_concurrency instead" + Rails.application.config.allow_concurrency + end + + def allow_concurrency=(value) + ActiveSupport::Deprecation.warn "ActionController::Base.allow_concurrency= is no longer effective. " << + "Please configure it on your application with config.allow_concurrency=" end def rescue_action(env) @@ -86,6 +99,9 @@ def cache_store=(store_option) end end + delegate :consider_all_requests_local, :consider_all_requests_local=, + :allow_concurrency, :allow_concurrency=, :to => :"self.class" + def render_to_body(options) if options.is_a?(Hash) && options.key?(:template) options[:template].sub!(/^\//, '') diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 05843a061b9264626e0b8e533b6615a2ab7c0370..1b5a4c308016ee22acd8ae2778e726ceacfb03e1 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActionController # The Rails framework provides a large number of helpers for working with +assets+, +dates+, +forms+, # +numbers+ and model objects, to name a few. These helpers are available to all templates @@ -50,7 +52,7 @@ module Helpers include AbstractController::Helpers included do - extlib_inheritable_accessor(:helpers_path) + class_attribute :helpers_path self.helpers_path = [] end diff --git a/actionpack/lib/action_controller/metal/hide_actions.rb b/actionpack/lib/action_controller/metal/hide_actions.rb index cdacdc40a606ab0ff85eff262a422750e7a3068b..e893acffdf65c44aad141a509f55f833a8b961b9 100644 --- a/actionpack/lib/action_controller/metal/hide_actions.rb +++ b/actionpack/lib/action_controller/metal/hide_actions.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActionController # ActionController::HideActions adds the ability to prevent public methods on a controller # to be called as actions. @@ -5,7 +7,8 @@ module HideActions extend ActiveSupport::Concern included do - extlib_inheritable_accessor(:hidden_actions) { Set.new } + class_attribute :hidden_actions + self.hidden_actions = Set.new end private @@ -14,7 +17,7 @@ module HideActions # action name is in the list of hidden actions. def action_method?(action_name) self.class.visible_action?(action_name) do - !hidden_actions.include?(action_name) && super + !self.class.hidden_actions.include?(action_name) && super end end @@ -24,7 +27,7 @@ module ClassMethods # ==== Parameters # *args<#to_s>:: A list of actions def hide_action(*args) - hidden_actions.merge(args.map! {|a| a.to_s }) + self.hidden_actions = hidden_actions.dup.merge(args.map(&:to_s)) end def inherited(klass) diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 08599d660eb50dc9c80c3529322e12157f43498f..e70a20b2be7be1580376878a4ae19c9dff2b5c06 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -1,11 +1,12 @@ require 'abstract_controller/collector' +require 'active_support/core_ext/class/attribute' module ActionController #:nodoc: module MimeResponds #:nodoc: extend ActiveSupport::Concern included do - extlib_inheritable_accessor :responder, :mimes_for_respond_to, :instance_writer => false + class_attribute :responder, :mimes_for_respond_to self.responder = ActionController::Responder clear_respond_to end @@ -38,18 +39,20 @@ def respond_to(*mimes) only_actions = Array(options.delete(:only)) except_actions = Array(options.delete(:except)) + new = mimes_for_respond_to.dup mimes.each do |mime| mime = mime.to_sym - mimes_for_respond_to[mime] = {} - mimes_for_respond_to[mime][:only] = only_actions unless only_actions.empty? - mimes_for_respond_to[mime][:except] = except_actions unless except_actions.empty? + new[mime] = {} + new[mime][:only] = only_actions unless only_actions.empty? + new[mime][:except] = except_actions unless except_actions.empty? end + self.mimes_for_respond_to = new.freeze end # Clear all mimes in respond_to. # def clear_respond_to - self.mimes_for_respond_to = ActiveSupport::OrderedHash.new + self.mimes_for_respond_to = ActiveSupport::OrderedHash.new.freeze end end @@ -218,12 +221,12 @@ def respond_to(*mimes, &block) # def respond_with(*resources, &block) raise "In order to use respond_with, first you need to declare the formats your " << - "controller responds to in the class level" if mimes_for_respond_to.empty? + "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.merge!(:default_response => response) - (options.delete(:responder) || responder).call(self, resources, options) + (options.delete(:responder) || self.class.responder).call(self, resources, options) end end @@ -235,8 +238,8 @@ def respond_with(*resources, &block) def collect_mimes_from_class_level #:nodoc: action = action_name.to_sym - mimes_for_respond_to.keys.select do |mime| - config = mimes_for_respond_to[mime] + self.class.mimes_for_respond_to.keys.select do |mime| + config = self.class.mimes_for_respond_to[mime] if config[:except] !config[:except].include?(action) diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index c1ba47927a837c4f6d07a5659d959438fe914bce..639b50874676926483f6fd28ad5df1479055020b 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActionController def self.add_renderer(key, &block) Renderers.add(key, &block) @@ -7,8 +9,8 @@ module Renderers extend ActiveSupport::Concern included do - extlib_inheritable_accessor :_renderers - self._renderers = {} + class_attribute :_renderers + self._renderers = {}.freeze end module ClassMethods @@ -30,9 +32,11 @@ def _handle_render_options(options) end def use_renderers(*args) + new = _renderers.dup args.each do |key| - _renderers[key] = RENDERERS[key] + new[key] = RENDERERS[key] end + self._renderers = new.freeze _write_render_options end alias use_renderer use_renderers diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index f1fb4d7ce5396108d585c4581e7f5cba923ef818..276c70330738e8e45faeb8368353fb05cbb1543a 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActionController #:nodoc: class InvalidAuthenticityToken < ActionControllerError #:nodoc: end @@ -13,7 +15,7 @@ module RequestForgeryProtection cattr_accessor :request_forgery_protection_token # Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode. - extlib_inheritable_accessor :allow_forgery_protection + class_attribute :allow_forgery_protection self.allow_forgery_protection = true helper_method :form_authenticity_token @@ -107,7 +109,7 @@ def form_authenticity_param end def protect_against_forgery? - allow_forgery_protection + self.class.allow_forgery_protection end end end diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb index d62269b9af11f936b59d2d759d832922d5563b8e..707ad968f4434f68f8d89078da2fe8f3ea39d7db 100644 --- a/actionpack/lib/action_controller/metal/testing.rb +++ b/actionpack/lib/action_controller/metal/testing.rb @@ -4,7 +4,7 @@ module Testing include RackDelegation - # OMG MEGA HAX + # TODO: Clean this up def process_with_new_base_test(request, response) @_request = request @_response = response diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 387e6a554b9e76cf095c87d01abdc98823293b16..51702368c1a23a504dbf9d8eef04363c76be7e45 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActionController # In routes.rb one defines URL-to-controller mappings, but the reverse # is also possible: an URL can be generated from one of your routing definitions. @@ -85,9 +87,8 @@ module UrlFor included do ActionController::Routing::Routes.install_helpers(self) - extlib_inheritable_accessor :default_url_options, - :instance_writer => false, :instance_reader => false - self.default_url_options ||= {} + class_attribute :default_url_options + self.default_url_options = {} end # Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 93aa69c060f096cb4e5e25cea3a8a97544808659..483be47adf09ea856925effc055168d6e2d90094 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -35,7 +35,6 @@ module ActionView autoload :Context autoload :Template autoload :Helpers - autoload :SafeBuffer autoload_under "render" do autoload :Partials @@ -56,7 +55,7 @@ module ActionView autoload :TestCase, 'action_view/test_case' end -require 'action_view/erb/util' +require 'active_support/core_ext/string/output_safety' require 'action_view/base' I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml" diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 07ef3f214078b146c7ca615de81effc5ec1e0e10..4096c296c357648632bb187cc27af3e0dc72a806 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/module/attr_internal' require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/class/attribute' module ActionView #:nodoc: class ActionViewError < StandardError #:nodoc: @@ -244,7 +245,7 @@ def self.process_view_paths(value) ActionView::PathSet.new(Array(value)) end - extlib_inheritable_accessor :helpers + class_attribute :helpers attr_reader :helpers def self.for_controller(controller) @@ -284,7 +285,7 @@ def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, @helpers = self.class.helpers || Module.new @_controller = controller - @_content_for = Hash.new {|h,k| h[k] = ActionView::SafeBuffer.new } + @_content_for = Hash.new {|h,k| h[k] = ActiveSupport::SafeBuffer.new } @_virtual_path = nil self.view_paths = view_paths end diff --git a/actionpack/lib/action_view/erb/util.rb b/actionpack/lib/action_view/erb/util.rb deleted file mode 100644 index aef859b3ac91114fa8b06516e8c708f46074e4af..0000000000000000000000000000000000000000 --- a/actionpack/lib/action_view/erb/util.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'erb' - -class ERB - module Util - HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' } - JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' } - - # A utility method for escaping HTML tag characters. - # This method is also aliased as h. - # - # In your ERb templates, use this method to escape any unsafe content. For example: - # <%=h @person.name %> - # - # ==== Example: - # puts html_escape("is a > 0 & a < 10?") - # # => is a > 0 & a < 10? - def html_escape(s) - s = s.to_s - if s.html_safe? - s - else - s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe! - end - end - - undef :h - alias h html_escape - - module_function :html_escape - module_function :h - - # A utility method for escaping HTML entities in JSON strings. - # This method is also aliased as j. - # - # In your ERb templates, use this method to escape any HTML entities: - # <%=j @person.to_json %> - # - # ==== Example: - # puts json_escape("is a > 0 & a < 10?") - # # => is a \u003E 0 \u0026 a \u003C 10? - def json_escape(s) - s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] } - end - - alias j json_escape - module_function :j - module_function :json_escape - end -end diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index 87b7adf6c4f7db2caf5a78b027fb21bd814f4a85..e106bb089738f0d681b21ae6929836a8dee0b62e 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -6,7 +6,7 @@ module ActionView class Base - @@field_error_proc = Proc.new{ |html_tag, instance| "
#{html_tag}
".html_safe! } + @@field_error_proc = Proc.new{ |html_tag, instance| "
#{html_tag}
".html_safe } cattr_accessor :field_error_proc end @@ -86,12 +86,11 @@ def form(record_name, options = {}) submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil) - contents << hidden_field(record_name, :id) unless record.new_record? - contents << all_input_tags(record, record_name, options) + contents.safe_concat hidden_field(record_name, :id) unless record.new_record? + contents.safe_concat all_input_tags(record, record_name, options) yield contents if block_given? - contents << submit_tag(submit_value) - contents << '' - contents.html_safe! + contents.safe_concat submit_tag(submit_value) + contents.safe_concat('') end # Returns a string containing the error message attached to the +method+ on the +object+ if one exists. diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 4df99f8293bce65e0f022ec77945c511eacdaaeb..96976ce45f8dfa9d0d4519cceeeff632e851675b 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -293,7 +293,7 @@ def javascript_include_tag(*sources) else sources = expand_javascript_sources(sources, recursive) ensure_javascript_sources!(sources) if cache - sources.collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe! + sources.collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe end end @@ -444,7 +444,7 @@ def stylesheet_link_tag(*sources) else sources = expand_stylesheet_sources(sources, recursive) ensure_stylesheet_sources!(sources) if cache - sources.collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe! + sources.collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe end end @@ -588,7 +588,7 @@ def video_tag(sources, options = {}) if sources.is_a?(Array) content_tag("video", options) do - sources.map { |source| tag("source", :src => source) }.join.html_safe! + sources.map { |source| tag("source", :src => source) }.join.html_safe end else options[:src] = path_to_video(sources) diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index b62df75dbb45c67fcb8a9200f4e1a61b4c900f92..8c48300ed3ee06cfbff39e9120afdcd991b2ecc4 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -143,7 +143,7 @@ def content_for?(name) # Defaults to a new empty string. def with_output_buffer(buf = nil) #:nodoc: unless buf - buf = ActionView::SafeBuffer.new + buf = ActiveSupport::SafeBuffer.new buf.force_encoding(output_buffer.encoding) if buf.respond_to?(:force_encoding) end self.output_buffer, old_buffer = buf, output_buffer diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 34f38b0a8a5ee2ec5355a5f81a69a9c71b94d0ac..8be2f76bd6950820902d51818baf4aede9d45197 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -616,7 +616,7 @@ def select_datetime build_selects_from_types(order) else - "#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe! + "#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe end end @@ -835,7 +835,7 @@ def build_select(type, select_options_as_html) select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt] select_html << select_options_as_html.to_s - (content_tag(:select, select_html, select_options) + "\n").html_safe! + (content_tag(:select, select_html, select_options) + "\n").html_safe end # Builds a prompt option tag with supplied options or from default options @@ -865,7 +865,7 @@ def build_hidden(type, value) :id => input_id_from_type(type), :name => input_name_from_type(type), :value => value - }) + "\n").html_safe! + }) + "\n").html_safe end # Returns the name attribute for the input tag @@ -896,7 +896,7 @@ def build_selects_from_types(order) separator = separator(type) unless type == order.first # don't add on last field select.insert(0, separator.to_s + send("select_#{type}").to_s) end - select.html_safe! + select.html_safe end # Returns the separator for a given datetime component @@ -916,15 +916,15 @@ def separator(type) class InstanceTag #:nodoc: def to_date_select_tag(options = {}, html_options = {}) - datetime_selector(options, html_options).select_date.html_safe! + datetime_selector(options, html_options).select_date.html_safe end def to_time_select_tag(options = {}, html_options = {}) - datetime_selector(options, html_options).select_time.html_safe! + datetime_selector(options, html_options).select_time.html_safe end def to_datetime_select_tag(options = {}, html_options = {}) - datetime_selector(options, html_options).select_datetime.html_safe! + datetime_selector(options, html_options).select_datetime.html_safe end private diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb index 885945fde3e6b9004fe7d4423493687cebd5eac4..e637dc1474a28c760657cef51dc8c08d8f28d88c 100644 --- a/actionpack/lib/action_view/helpers/debug_helper.rb +++ b/actionpack/lib/action_view/helpers/debug_helper.rb @@ -27,10 +27,10 @@ module DebugHelper def debug(object) begin Marshal::dump(object) - "
#{h(object.to_yaml).gsub("  ", "  ")}
".html_safe! + "
#{h(object.to_yaml).gsub("  ", "  ")}
".html_safe rescue Exception => e # errors from Marshal or YAML # Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback - "#{h(object.inspect)}".html_safe! + "#{h(object.inspect)}".html_safe end end end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 157deebe40af6fd0e92460c4ee4aab510892e2fa..1d91b6957a33c74d56e2b50f506f076618ba65de 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -225,6 +225,33 @@ module FormHelper # ... # <% end %> # + # === Unobtrusive JavaScript + # + # Specifying: + # + # :remote => true + # + # in the options hash creates a form that will allow the unobtrusive JavaScript drivers to modify its + # behaviour. The expected default behaviour is an XMLHttpRequest in the background instead of the regular + # POST arrangement, but ultimately the behaviour is the choice of the JavaScript driver implementor. + # Even though it's using JavaScript to serialize the form elements, the form submission will work just like + # a regular submission as viewed by the receiving side (all elements available in params). + # + # Example: + # + # <% form_for(:post, @post, :remote => true, :html => { :id => 'create-post', :method => :put }) do |f| %> + # ... + # <% end %> + # + # The HTML generated for this would be: + # + #
+ #
+ # + #
+ # ... + #
+ # # === Customized form builders # # You can also build forms using a customized FormBuilder class. Subclass @@ -280,9 +307,11 @@ def form_for(record_or_name_or_array, *args, &proc) args.unshift object end + options[:html][:remote] = true if options.delete(:remote) + concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {})) fields_for(object_name, *(args << options), &proc) - concat(''.html_safe!) + safe_concat('') end def apply_form_for_options!(object_or_array, options) #:nodoc: @@ -850,7 +879,7 @@ def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0") end hidden = tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value) checkbox = tag("input", options) - (hidden + checkbox).html_safe! + (hidden + checkbox).html_safe end def to_boolean_select_tag(options = {}) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index d3e614b98f1cc9b891c89c0e58257497628e2876..21acfbbee8f6ac2606946e299ae7f266f0ef1934 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -296,7 +296,7 @@ def options_for_select(container, selected = nil) options << %() end - options_for_select.join("\n").html_safe! + options_for_select.join("\n").html_safe end # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index fb32f78e5bf568378c94a7c883fb6030c4c55365..9b8471c6c61b72dc05e7b13cb5fa323f01c0aeb9 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -19,6 +19,8 @@ module FormTagHelper # If "put", "delete", or another verb is used, a hidden input with name _method # is added to simulate the verb over post. # * A list of parameters to feed to the URL the form will be posted to. + # * :remote - If set to true, will allow the Unobtrusive JavaScript drivers to control the + # submit behaviour. By default this behaviour is an ajax submit. # # ==== Examples # form_tag('/posts') @@ -30,10 +32,14 @@ module FormTagHelper # form_tag('/upload', :multipart => true) # # =>
# - # <% form_tag '/posts' do -%> + # <% form_tag('/posts')do -%> #
<%= submit_tag 'Save' %>
# <% end -%> # # =>
+ # + # <% form_tag('/posts', :remote => true) %> + # # =>
+ # def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block) html_options = html_options_for_form(url_for_options, options, *parameters_for_url) if block_given? @@ -333,12 +339,13 @@ def radio_button_tag(name, value, checked = false, options = {}) # Creates a submit button with the text value as the caption. # # ==== Options - # * :confirm => 'question?' - This will add a JavaScript confirm - # prompt with the question specified. If the user accepts, the form is - # processed normally, otherwise no action is taken. + # * :confirm => 'question?' - If present the unobtrusive JavaScript + # drivers will provide a prompt with the question specified. If the user accepts, + # the form is processed normally, otherwise no action is taken. # * :disabled - If true, the user will not be able to use this input. - # * :disable_with - Value of this parameter will be used as the value for a disabled version - # of the submit button when the form is submitted. + # * :disable_with - Value of this parameter will be used as the value for a + # disabled version of the submit button when the form is submitted. This feature is + # provided by the unobtrusive JavaScript driver. # * Any other key creates standard HTML options for the tag. # # ==== Examples @@ -351,16 +358,22 @@ def radio_button_tag(name, value, checked = false, options = {}) # submit_tag "Save edits", :disabled => true # # => # + # # submit_tag "Complete sale", :disable_with => "Please wait..." - # # => # # submit_tag nil, :class => "form_submit" # # => # # submit_tag "Edit", :disable_with => "Editing...", :class => "edit-button" - # # => + # + # submit_tag "Save", :confirm => "Are you sure?" + # # => + # def submit_tag(value = "Save changes", options = {}) options.stringify_keys! @@ -433,7 +446,7 @@ def field_set_tag(legend = nil, options = nil, &block) concat(tag(:fieldset, options, true)) concat(content_tag(:legend, legend)) unless legend.blank? concat(content) - concat("".html_safe!) + safe_concat("") end private @@ -441,6 +454,7 @@ def html_options_for_form(url_for_options, options, *parameters_for_url) returning options.stringify_keys do |html_options| html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart") html_options["action"] = url_for(url_for_options, *parameters_for_url) + html_options["data-remote"] = true if html_options.delete("remote") end end @@ -460,14 +474,14 @@ def extra_tags_for_form(html_options) def form_tag_html(html_options) extra_tags = extra_tags_for_form(html_options) - (tag(:form, html_options, true) + extra_tags).html_safe! + (tag(:form, html_options, true) + extra_tags).html_safe end def form_tag_in_block(html_options, &block) content = capture(&block) concat(form_tag_html(html_options)) concat(content) - concat("
".html_safe!) + safe_concat("") end def token_tag diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 64b71663c37390635135845d7e9e171edb438325..3d3502a08bce9ed9daef274d80cda9e6a12448ef 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -92,7 +92,7 @@ def number_to_currency(number, options = {}) :precision => precision, :delimiter => delimiter, :separator => separator) - ).gsub(/%u/, unit).html_safe! + ).gsub(/%u/, unit).html_safe rescue number end diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index d335d89274c70a93d5369557df0f278430c78f30..7eb6bceca0a7afbb20f1444d33952057f27e76e3 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -610,7 +610,7 @@ def method_missing(method, *arguments) # page.hide 'spinner' # end def update_page(&block) - JavaScriptGenerator.new(@template, &block).to_s.html_safe! + JavaScriptGenerator.new(@template, &block).to_s.html_safe end # Works like update_page but wraps the generated JavaScript in a d e f", "a b cd e f" end - # fucked + # TODO: Clean up def test_sanitize_js_handlers raw = %{onthis="do that" hello} assert_sanitized raw, %{onthis="do that" hello} @@ -193,7 +193,7 @@ def test_should_not_fall_for_ridiculous_hack assert_sanitized img_hack, "" end - # fucked + # TODO: Clean up def test_should_sanitize_attributes assert_sanitized %(blah), %(blah) end diff --git a/actionpack/test/template/subscriber_test.rb b/actionpack/test/template/subscriber_test.rb index 5db2b16ac1f7c23323054bf627e117a92015e080..8bacab70887f9a9cf2fbfac766bcc604acad2b01 100644 --- a/actionpack/test/template/subscriber_test.rb +++ b/actionpack/test/template/subscriber_test.rb @@ -33,7 +33,7 @@ def test_render_file_template end def test_render_text_template - @view.render(:text => "OMG") + @view.render(:text => "TEXT") wait assert_equal 1, @logger.logged(:info).size @@ -41,7 +41,7 @@ def test_render_text_template end def test_render_inline_template - @view.render(:inline => "<%= 'OMG' %>") + @view.render(:inline => "<%= 'TEXT' %>") wait assert_equal 1, @logger.logged(:info).size diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb index 9a448ce328b564aedebfd20fe89abf24fd29d157..be2c6b3108803dbe3644fac4f9ff85631c9ba9ec 100644 --- a/actionpack/test/template/test_case_test.rb +++ b/actionpack/test/template/test_case_test.rb @@ -160,7 +160,7 @@ def from_test_case; 'Word!'; end class AssertionsTest < ActionView::TestCase def render_from_helper form_tag('/foo') do - concat render(:text => '').html_safe! + safe_concat render(:text => '') end end helper_method :render_from_helper diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index b498ec84299512b6a1473064d992690a8e6fda89..e904e88f496422e73f5ef97b69058528ef34c302 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -81,6 +81,13 @@ def test_button_to_with_javascript_confirm ) end + def test_button_to_with_remote_and_javascript_confirm + assert_dom_equal( + "
", + button_to("Hello", "http://www.example.com", :remote => true, :confirm => "Are you sure?") + ) + end + def test_button_to_enabled_disabled assert_dom_equal( "
", diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb index 917bb720d060650715cfd9d3c626b45b5518062d..8bcbe546516cd39305dbe176807d54288f3e2270 100644 --- a/activemodel/test/cases/helper.rb +++ b/activemodel/test/cases/helper.rb @@ -1,10 +1,4 @@ -begin - require File.expand_path('../../../../vendor/gems/environment', __FILE__) -rescue LoadError -end - -lib = File.expand_path('../../../lib', __FILE__) -$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) +require File.expand_path('../../../../load_paths', __FILE__) require 'config' require 'active_model' diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index c84a3ac5a982afad4c42fd8f7b265cf0f915c2f1..4fd1a0213c170aabf5432a461b0d476a3921446b 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -9,7 +9,7 @@ s.add_dependency('activesupport', '= 3.0.pre') s.add_dependency('activemodel', '= 3.0.pre') - s.add_dependency('arel', '= 0.2.pre') + s.add_dependency('arel', '~> 0.2.0') s.require_path = 'lib' s.autorequire = 'active_record' diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 4e05b819b52f006ce92fe4eb31dcc32154aada2a..0fbb1f0261dda72fabf4c0166ef9a9af5d12da8f 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActiveRecord # Observer classes respond to lifecycle callbacks to implement trigger-like # behavior outside the original class. This is a great way to reduce the @@ -85,7 +87,8 @@ module ActiveRecord # singletons and that call instantiates and registers them. # class Observer < ActiveModel::Observer - extlib_inheritable_accessor(:observed_methods){ [] } + class_attribute :observed_methods + self.observed_methods = [] def initialize super @@ -93,7 +96,7 @@ def initialize end def self.method_added(method) - observed_methods << method if ActiveRecord::Callbacks::CALLBACKS.include?(method.to_sym) + self.observed_methods += [method] if ActiveRecord::Callbacks::CALLBACKS.include?(method.to_sym) end protected @@ -106,7 +109,7 @@ def add_observer!(klass) # Check if a notifier callback was already added to the given class. If # it was not, add it. - self.observed_methods.each do |method| + self.class.observed_methods.each do |method| callback = :"_notify_observers_for_#{method}" if (klass.instance_methods & [callback, callback.to_s]).empty? klass.class_eval "def #{callback}; notify_observers(:#{method}); end" diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index fa76e2d57a652c7242f21e6f8cbc04b121cf3a41..9e8bfbbee87386160d4673f4eb540ef8567844bf 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -1,14 +1,7 @@ -begin - require File.expand_path('../../../../vendor/gems/environment', __FILE__) -rescue LoadError -end - -lib = File.expand_path('../../../lib', __FILE__) -$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) +require File.expand_path('../../../../load_paths', __FILE__) require 'config' -require 'rubygems' require 'test/unit' require 'stringio' diff --git a/activeresource/test/abstract_unit.rb b/activeresource/test/abstract_unit.rb index 1e71d5d0dd355b97d24cc080308278494dbc7a8b..2f43916521fba5f55ddfe0b3248e86b23aa8902a 100644 --- a/activeresource/test/abstract_unit.rb +++ b/activeresource/test/abstract_unit.rb @@ -1,10 +1,4 @@ -begin - require File.expand_path('../../../vendor/gems/environment', __FILE__) -rescue LoadError -end - -lib = File.expand_path('../../lib', __FILE__) -$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) +require File.expand_path('../../../load_paths', __FILE__) require 'rubygems' require 'test/unit' diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 787fa26e448db1faa4e726e73b0e0aa9a57ccda5..431607f4e08b2886e886ca4f85112be2c5b78de7 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0 (pending)* +* Introduce class_attribute to declare inheritable class attributes. Writing an attribute on a subclass behaves just like overriding the superclass reader method. Unifies and replaces most usage of cattr_accessor, class_inheritable_attribute, superclass_delegating_attribute, and extlib_inheritable_attribute. [Jeremy Kemper, Yehuda Katz] + * Time#- with a DateTime argument behaves the same as with a Time argument, i.e. returns the difference between self and arg as a Float #3476 [Geoff Buesing] * YAML serialization for OrderedHash. #3608 [Gregor Schmidt] diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 833ae351b93a6e955a282e84d05f2d349030383c..ae31d191c0874702b2b5bf0d861c7b8e28f81909 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -67,5 +67,6 @@ module ActiveSupport autoload :XmlMini end + autoload :SafeBuffer, "active_support/core_ext/string/output_safety" autoload :TestCase end diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb new file mode 100644 index 0000000000000000000000000000000000000000..d74219cb931c8b18976e4260005ce7071c7af347 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/class/attribute.rb @@ -0,0 +1,36 @@ +require 'active_support/core_ext/object/metaclass' +require 'active_support/core_ext/module/delegation' + +class Class + # Declare a class-level attribute whose value is inheritable and + # overwritable by subclasses: + # + # class Base + # class_attribute :setting + # end + # + # class Subclass < Base + # end + # + # Base.setting = true + # Subclass.setting # => true + # Subclass.setting = false + # Subclass.setting # => false + # Base.setting # => true + # + # This matches normal Ruby method inheritance: think of writing an attribute + # on a subclass as overriding the reader method. + # + # For convenience, a query method is defined as well: + # + # Subclass.setting? # => false + def class_attribute(*attrs) + attrs.each do |attr| + metaclass.send(:define_method, attr) { } + metaclass.send(:define_method, "#{attr}?") { !!send(attr) } + metaclass.send(:define_method, "#{attr}=") do |value| + metaclass.send(:define_method, attr) { value } + end + end + end +end 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 ceed90ce79c53329d9b995db7f761ecacc90d0a4..3977971e8d9f80f7fead9b808a806b6225e42523 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -1,3 +1,53 @@ +require "erb" + +class ERB + module Util + HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' } + JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' } + + # A utility method for escaping HTML tag characters. + # This method is also aliased as h. + # + # In your ERb templates, use this method to escape any unsafe content. For example: + # <%=h @person.name %> + # + # ==== Example: + # puts html_escape("is a > 0 & a < 10?") + # # => is a > 0 & a < 10? + def html_escape(s) + s = s.to_s + if s.html_safe? + s + else + s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe + end + end + + undef :h + alias h html_escape + + module_function :html_escape + module_function :h + + # A utility method for escaping HTML entities in JSON strings. + # This method is also aliased as j. + # + # In your ERb templates, use this method to escape any HTML entities: + # <%=j @person.to_json %> + # + # ==== Example: + # puts json_escape("is a > 0 & a < 10?") + # # => is a \u003E 0 \u0026 a \u003C 10? + def json_escape(s) + s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] } + end + + alias j json_escape + module_function :j + module_function :json_escape + end +end + class Object def html_safe? false @@ -10,32 +60,46 @@ def html_safe? end end -class String - attr_accessor :_rails_html_safe - alias html_safe? _rails_html_safe +module ActiveSupport #:nodoc: + class SafeBuffer < String + alias safe_concat concat - def html_safe! - @_rails_html_safe = true - self - end + def concat(value) + if value.html_safe? + super(value) + else + super(ERB::Util.h(value)) + end + end - def html_safe - dup.html_safe! - end + def +(other) + dup.concat(other) + end + + def <<(value) + self.concat(value) + end + + def html_safe? + true + end + + def html_safe + self + end - alias original_plus + - def +(other) - result = original_plus(other) - result._rails_html_safe = html_safe? && other.html_safe? - result + def to_s + self + end end +end - alias original_concat << - alias safe_concat << - def <<(other) - @_rails_html_safe = false unless other.html_safe? - result = original_concat(other) +class String + def html_safe! + raise "You can't call html_safe! on a String" end - alias concat << + def html_safe + ActiveSupport::SafeBuffer.new(self) + end end \ No newline at end of file diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index 6e660f86478a35661ddc2988347fca687e3c5452..e4c1651acf10ba427cc548b8931b3cdfb71cf492 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/proc' require 'active_support/core_ext/string/inflections' require 'active_support/core_ext/array/extract_options' @@ -9,7 +9,7 @@ module Rescuable extend Concern included do - class_inheritable_accessor :rescue_handlers + class_attribute :rescue_handlers self.rescue_handlers = [] end @@ -67,7 +67,7 @@ def rescue_from(*klasses, &block) end # put the new handler at the end because the list is read in reverse - rescue_handlers << [key, options[:with]] + self.rescue_handlers += [[key, options[:with]]] end end end @@ -83,7 +83,7 @@ def rescue_with_handler(exception) def handler_for_rescue(exception) # We go from right to left because pairs are pushed onto rescue_handlers # as rescue_from declarations are found. - _, rescuer = rescue_handlers.reverse.detect do |klass_name, handler| + _, rescuer = self.class.rescue_handlers.reverse.detect do |klass_name, handler| # The purpose of allowing strings in rescue_from is to support the # declaration of handler associations for exception classes whose # definition is yet unknown. diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index d91e0415c4773d68e3b76af0a4b3730da77facf9..33be6f65bfe80416debc56f7038cb934ca753af2 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -1,12 +1,4 @@ -ORIG_ARGV = ARGV.dup - -begin - require File.expand_path('../../../vendor/gems/environment', __FILE__) -rescue LoadError -end - -lib = File.expand_path("#{File.dirname(__FILE__)}/../lib") -$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) +require File.expand_path('../../../load_paths', __FILE__) require 'test/unit' require 'mocha' diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index df98644436d16ba99304030ee2f83330ec64e26e..11494e951e92b9993f3da908fa18d4869e9fa86a 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -264,12 +264,12 @@ class HyphenatedCallbacks define_callbacks :save attr_reader :stuff - set_callback :save, :before, :omg, :per_key => {:if => :yes} + set_callback :save, :before, :action, :per_key => {:if => :yes} def yes() true end - def omg - @stuff = "OMG" + def action + @stuff = "ACTION" end def save @@ -522,7 +522,7 @@ class HyphenatedKeyTest < Test::Unit::TestCase def test_save obj = HyphenatedCallbacks.new obj.save - assert_equal obj.stuff, "OMG" + assert_equal obj.stuff, "ACTION" end end end diff --git a/activesupport/test/core_ext/class/attribute_test.rb b/activesupport/test/core_ext/class/attribute_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..ef84b9f2554133b172c716fea639eb019aa93681 --- /dev/null +++ b/activesupport/test/core_ext/class/attribute_test.rb @@ -0,0 +1,47 @@ +require 'abstract_unit' +require 'active_support/core_ext/class/attribute' + +class ClassAttributeTest < ActiveSupport::TestCase + class Base + class_attribute :setting + end + + class Subclass < Base + end + + def setup + @klass = Class.new { class_attribute :setting } + @sub = Class.new(@klass) + end + + test 'defaults to nil' do + assert_nil @klass.setting + assert_nil @sub.setting + end + + test 'inheritable' do + @klass.setting = 1 + assert_equal 1, @sub.setting + end + + test 'overridable' do + @sub.setting = 1 + assert_nil @klass.setting + + @klass.setting = 2 + assert_equal 1, @sub.setting + + assert_equal 1, Class.new(@sub).setting + end + + test 'query method' do + assert_equal false, @klass.setting? + @klass.setting = 1 + assert_equal true, @klass.setting? + end + + test 'no instance delegates' do + assert_raise(NoMethodError) { @klass.new.setting } + assert_raise(NoMethodError) { @klass.new.setting? } + end +end diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 9a805bc0100bfafb2ceb9eb4abccd64d2d93406f..ca26f91e8c95a9ca8ec17d096838f970820f837d 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -342,12 +342,12 @@ def setup end test "A string can be marked safe" do - @string.html_safe! - assert @string.html_safe? + string = @string.html_safe + assert string.html_safe? end test "Marking a string safe returns the string" do - assert_equal @string, @string.html_safe! + assert_equal @string, @string.html_safe end test "A fixnum is safe by default" do @@ -361,7 +361,7 @@ def to_str end end - @string.html_safe! + @string.html_safe @string << klass.new assert_equal "helloother", @string @@ -369,44 +369,44 @@ def to_str end test "Adding a safe string to another safe string returns a safe string" do - @other_string = "other".html_safe! - @string.html_safe! - @combination = @other_string + @string + @other_string = "other".html_safe + string = @string.html_safe + @combination = @other_string + string assert_equal "otherhello", @combination assert @combination.html_safe? end - test "Adding an unsafe string to a safe string returns an unsafe string" do - @other_string = "other".html_safe! - @combination = @other_string + @string - @other_combination = @string + @other_string + test "Adding an unsafe string to a safe string escapes it and returns a safe string" do + @other_string = "other".html_safe + @combination = @other_string + "" + @other_combination = @string + "" - assert_equal "otherhello", @combination - assert_equal "helloother", @other_combination + assert_equal "other<foo>", @combination + assert_equal "hello", @other_combination - assert !@combination.html_safe? + assert @combination.html_safe? assert !@other_combination.html_safe? end test "Concatting safe onto unsafe yields unsafe" do @other_string = "other" - @string.html_safe! + @string.html_safe @other_string.concat(@string) assert !@other_string.html_safe? end - test "Concatting unsafe onto safe yields unsafe" do - @other_string = "other".html_safe! - - @other_string.concat(@string) - assert !@other_string.html_safe? + test "Concatting unsafe onto safe yields escaped safe" do + @other_string = "other".html_safe + string = @other_string.concat("") + assert_equal "other<foo>", string + assert string.html_safe? end test "Concatting safe onto safe yields safe" do - @other_string = "other".html_safe! - @string.html_safe! + @other_string = "other".html_safe + @string.html_safe @other_string.concat(@string) assert @other_string.html_safe? @@ -414,31 +414,32 @@ def to_str test "Concatting safe onto unsafe with << yields unsafe" do @other_string = "other" - @string.html_safe! + @string.html_safe @other_string << @string assert !@other_string.html_safe? end - test "Concatting unsafe onto safe with << yields unsafe" do - @other_string = "other".html_safe! - - @other_string << @string - assert !@other_string.html_safe? + test "Concatting unsafe onto safe with << yields escaped safe" do + @other_string = "other".html_safe + string = @other_string << "" + assert_equal "other<foo>", string + assert string.html_safe? end test "Concatting safe onto safe with << yields safe" do - @other_string = "other".html_safe! - @string.html_safe! + @other_string = "other".html_safe + @string.html_safe @other_string << @string assert @other_string.html_safe? end test "Concatting a fixnum to safe always yields safe" do - @string.html_safe! - @string.concat(13) - assert @string.html_safe? + string = @string.html_safe + string = string.concat(13) + assert_equal "hello".concat(13), string + assert string.html_safe? end end diff --git a/activesupport/test/fixtures/custom.rb b/activesupport/test/fixtures/custom.rb new file mode 100644 index 0000000000000000000000000000000000000000..0eefce0c25fed721e635c89416e12532ede67e6e --- /dev/null +++ b/activesupport/test/fixtures/custom.rb @@ -0,0 +1,2 @@ +class Custom +end \ No newline at end of file diff --git a/activesupport/test/fixtures/omgomg.rb b/activesupport/test/fixtures/omgomg.rb deleted file mode 100644 index a512a93ae46d1fd5e91e91d650806fb85977fd39..0000000000000000000000000000000000000000 --- a/activesupport/test/fixtures/omgomg.rb +++ /dev/null @@ -1,2 +0,0 @@ -class OmgOmg -end \ No newline at end of file diff --git a/activesupport/test/isolation_test.rb b/activesupport/test/isolation_test.rb index a7af5e96f6d8a9d43e063664a10d1756353cb595..2c2986ea28f9a4f7d34a3761ef54b135db464da7 100644 --- a/activesupport/test/isolation_test.rb +++ b/activesupport/test/isolation_test.rb @@ -59,15 +59,15 @@ def teardown end test "resets requires one" do - assert !defined?(OmgOmg) - assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size - require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg")) + assert !defined?(Custom) + assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/custom/).size + require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "custom")) end test "resets requires two" do - assert !defined?(OmgOmg) - assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size - require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg")) + assert !defined?(Custom) + assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/custom/).size + require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "custom")) end end else diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 0e489c10e1f1eb5070c014bb707f4d4328634759..0f68dcfe23495ac9480d830123bf9a974bfe84f2 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -301,10 +301,10 @@ def test_rjust_should_count_characters_instead_of_bytes assert_equal " #{UNICODE_STRING}", @chars.rjust(5) assert_equal " #{UNICODE_STRING}", @chars.rjust(7) assert_equal "---#{UNICODE_STRING}", @chars.rjust(7, '-') - assert_equal "ααα#{UNICODE_STRING}", @chars.rjust(7, 'α') + assert_equal "αα#{UNICODE_STRING}", @chars.rjust(7, 'α') assert_equal "aba#{UNICODE_STRING}", @chars.rjust(7, 'ab') assert_equal "αηα#{UNICODE_STRING}", @chars.rjust(7, 'αη') - assert_equal "αηαη#{UNICODE_STRING}", @chars.rjust(8, 'αη') + assert_equal "αη#{UNICODE_STRING}", @chars.rjust(8, 'αη') end def test_ljust_should_raise_argument_errors_on_bad_arguments @@ -319,10 +319,10 @@ def test_ljust_should_count_characters_instead_of_bytes assert_equal "#{UNICODE_STRING} ", @chars.ljust(5) assert_equal "#{UNICODE_STRING} ", @chars.ljust(7) assert_equal "#{UNICODE_STRING}---", @chars.ljust(7, '-') - assert_equal "#{UNICODE_STRING}ααα", @chars.ljust(7, 'α') + assert_equal "#{UNICODE_STRING}αα", @chars.ljust(7, 'α') assert_equal "#{UNICODE_STRING}aba", @chars.ljust(7, 'ab') assert_equal "#{UNICODE_STRING}αηα", @chars.ljust(7, 'αη') - assert_equal "#{UNICODE_STRING}αηαη", @chars.ljust(8, 'αη') + assert_equal "#{UNICODE_STRING}αη", @chars.ljust(8, 'αη') end def test_center_should_raise_argument_errors_on_bad_arguments @@ -339,13 +339,13 @@ def test_center_should_count_charactes_instead_of_bytes assert_equal " #{UNICODE_STRING} ", @chars.center(7) assert_equal "--#{UNICODE_STRING}--", @chars.center(8, '-') assert_equal "--#{UNICODE_STRING}---", @chars.center(9, '-') - assert_equal "αα#{UNICODE_STRING}αα", @chars.center(8, 'α') - assert_equal "αα#{UNICODE_STRING}ααα", @chars.center(9, 'α') - assert_equal "a#{UNICODE_STRING}ab", @chars.center(7, 'ab') - assert_equal "ab#{UNICODE_STRING}ab", @chars.center(8, 'ab') - assert_equal "abab#{UNICODE_STRING}abab", @chars.center(12, 'ab') - assert_equal "α#{UNICODE_STRING}αη", @chars.center(7, 'αη') - assert_equal "αη#{UNICODE_STRING}αη", @chars.center(8, 'αη') + assert_equal "α#{UNICODE_STRING}α", @chars.center(8, 'α') + assert_equal "α#{UNICODE_STRING}αα", @chars.center(9, 'α') + assert_equal "a#{UNICODE_STRING}", @chars.center(7, 'ab') + assert_equal UNICODE_STRING, @chars.center(8, 'ab') + assert_equal "ab#{UNICODE_STRING}ab", @chars.center(12, 'ab') + assert_equal "α#{UNICODE_STRING}", @chars.center(7, 'αη') + assert_equal UNICODE_STRING, @chars.center(8, 'αη') end def test_lstrip_strips_whitespace_from_the_left_of_the_string diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index d3af535c26c38146b14a4afe6e7eb914e2b4b2fc..0b78b53c736ebbaaa1a9969f06746f8c82d26433 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -77,7 +77,7 @@ def test_instrument_returns_block_result def test_instrument_with_bang_returns_result_even_on_failure begin instrument!(:awesome, :payload => "notifications") do - raise "OMG" + raise "FAIL" end flunk rescue @@ -126,10 +126,10 @@ def test_nested_events_can_be_instrumented def test_instrument_does_not_publish_when_exception_is_raised begin instrument(:awesome, :payload => "notifications") do - raise "OMG" + raise "FAIL" end rescue RuntimeError => e - assert_equal "OMG", e.message + assert_equal "FAIL", e.message end drain diff --git a/actionpack/test/template/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb similarity index 81% rename from actionpack/test/template/safe_buffer_test.rb rename to activesupport/test/safe_buffer_test.rb index 6a18201d168433d34c5ff0da40ed03dba4c8c054..bf61f9e58c47ee7ab1fadc2676601523c184caa9 100644 --- a/actionpack/test/template/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -1,8 +1,8 @@ require 'abstract_unit' -class SafeBufferTest < ActionView::TestCase +class SafeBufferTest < ActiveSupport::TestCase def setup - @buffer = ActionView::SafeBuffer.new + @buffer = ActiveSupport::SafeBuffer.new end test "Should look like a string" do @@ -16,7 +16,7 @@ def setup end test "Should NOT escape a safe value passed to it" do - @buffer << "