mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge remote branch 'thedarkone/performance'
This commit is contained in:
commit
756b32ef39
16 changed files with 180 additions and 77 deletions
|
@ -5,16 +5,18 @@ module ActionController
|
||||||
include AbstractController::UrlFor
|
include AbstractController::UrlFor
|
||||||
|
|
||||||
def url_options
|
def url_options
|
||||||
options = {}
|
@_url_options ||= begin
|
||||||
if _routes.equal?(env["action_dispatch.routes"])
|
options = {}
|
||||||
options[:script_name] = request.script_name.dup
|
if _routes.equal?(env["action_dispatch.routes"])
|
||||||
end
|
options[:script_name] = request.script_name.dup
|
||||||
|
end
|
||||||
|
|
||||||
super.merge(options).reverse_merge(
|
super.merge(options).reverse_merge(
|
||||||
:host => request.host_with_port,
|
:host => request.host_with_port,
|
||||||
:protocol => request.protocol,
|
:protocol => request.protocol,
|
||||||
:_path_segments => request.symbolized_path_parameters
|
:_path_segments => request.symbolized_path_parameters
|
||||||
)
|
).freeze
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,6 +26,10 @@ module ActionController
|
||||||
options.stylesheets_dir ||= paths.public.stylesheets.to_a.first
|
options.stylesheets_dir ||= paths.public.stylesheets.to_a.first
|
||||||
options.page_cache_directory ||= paths.public.to_a.first
|
options.page_cache_directory ||= paths.public.to_a.first
|
||||||
|
|
||||||
|
# make sure readers methods get compiled
|
||||||
|
options.asset_path ||= nil
|
||||||
|
options.asset_host ||= nil
|
||||||
|
|
||||||
ActiveSupport.on_load(:action_controller) do
|
ActiveSupport.on_load(:action_controller) do
|
||||||
include app.routes.mounted_helpers
|
include app.routes.mounted_helpers
|
||||||
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
|
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
|
||||||
|
@ -33,5 +37,11 @@ module ActionController
|
||||||
options.each { |k,v| send("#{k}=", v) }
|
options.each { |k,v| send("#{k}=", v) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
config.after_initialize do
|
||||||
|
ActiveSupport.on_load(:action_controller) do
|
||||||
|
config.crystalize! if config.respond_to?(:crystalize!)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,12 +15,12 @@ module ActionDispatch
|
||||||
|
|
||||||
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
||||||
def protocol
|
def protocol
|
||||||
ssl? ? 'https://' : 'http://'
|
@protocol ||= ssl? ? 'https://' : 'http://'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Is this an SSL request?
|
# Is this an SSL request?
|
||||||
def ssl?
|
def ssl?
|
||||||
@env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
|
@ssl ||= @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the \host for this request, such as "example.com".
|
# Returns the \host for this request, such as "example.com".
|
||||||
|
|
|
@ -105,7 +105,7 @@ module ActionDispatch
|
||||||
else [ record_or_hash_or_array ]
|
else [ record_or_hash_or_array ]
|
||||||
end
|
end
|
||||||
|
|
||||||
inflection = if options[:action].to_s == "new"
|
inflection = if options[:action] && options[:action].to_s == "new"
|
||||||
args.pop
|
args.pop
|
||||||
:singular
|
:singular
|
||||||
elsif (record.respond_to?(:persisted?) && !record.persisted?)
|
elsif (record.respond_to?(:persisted?) && !record.persisted?)
|
||||||
|
@ -168,10 +168,7 @@ module ActionDispatch
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_named_route_call(records, inflection, options = {})
|
def build_named_route_call(records, inflection, options = {})
|
||||||
unless records.is_a?(Array)
|
if records.is_a?(Array)
|
||||||
record = extract_record(records)
|
|
||||||
route = []
|
|
||||||
else
|
|
||||||
record = records.pop
|
record = records.pop
|
||||||
route = records.map do |parent|
|
route = records.map do |parent|
|
||||||
if parent.is_a?(Symbol) || parent.is_a?(String)
|
if parent.is_a?(Symbol) || parent.is_a?(String)
|
||||||
|
@ -180,6 +177,9 @@ module ActionDispatch
|
||||||
ActiveModel::Naming.route_key(parent).singularize
|
ActiveModel::Naming.route_key(parent).singularize
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
record = extract_record(records)
|
||||||
|
route = []
|
||||||
end
|
end
|
||||||
|
|
||||||
if record.is_a?(Symbol) || record.is_a?(String)
|
if record.is_a?(Symbol) || record.is_a?(String)
|
||||||
|
|
|
@ -334,6 +334,19 @@ module ActionDispatch
|
||||||
end
|
end
|
||||||
|
|
||||||
class Generator #:nodoc:
|
class Generator #:nodoc:
|
||||||
|
PARAMETERIZE = {
|
||||||
|
:parameterize => lambda do |name, value|
|
||||||
|
if name == :controller
|
||||||
|
value
|
||||||
|
elsif value.is_a?(Array)
|
||||||
|
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
||||||
|
else
|
||||||
|
return nil unless param = value.to_param
|
||||||
|
param.split('/').map { |v| Rack::Mount::Utils.escape_uri(v) }.join("/")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
attr_reader :options, :recall, :set, :named_route
|
attr_reader :options, :recall, :set, :named_route
|
||||||
|
|
||||||
def initialize(options, recall, set, extras = false)
|
def initialize(options, recall, set, extras = false)
|
||||||
|
@ -422,7 +435,7 @@ module ActionDispatch
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate
|
def generate
|
||||||
path, params = @set.set.generate(:path_info, named_route, options, recall, opts)
|
path, params = @set.set.generate(:path_info, named_route, options, recall, PARAMETERIZE)
|
||||||
|
|
||||||
raise_routing_error unless path
|
raise_routing_error unless path
|
||||||
|
|
||||||
|
@ -430,26 +443,12 @@ module ActionDispatch
|
||||||
|
|
||||||
return [path, params.keys] if @extras
|
return [path, params.keys] if @extras
|
||||||
|
|
||||||
path << "?#{params.to_query}" if params.any?
|
path << "?#{params.to_query}" unless params.empty?
|
||||||
path
|
path
|
||||||
rescue Rack::Mount::RoutingError
|
rescue Rack::Mount::RoutingError
|
||||||
raise_routing_error
|
raise_routing_error
|
||||||
end
|
end
|
||||||
|
|
||||||
def opts
|
|
||||||
parameterize = lambda do |name, value|
|
|
||||||
if name == :controller
|
|
||||||
value
|
|
||||||
elsif value.is_a?(Array)
|
|
||||||
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
|
||||||
else
|
|
||||||
return nil unless param = value.to_param
|
|
||||||
param.split('/').map { |v| Rack::Mount::Utils.escape_uri(v) }.join("/")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
{:parameterize => parameterize}
|
|
||||||
end
|
|
||||||
|
|
||||||
def raise_routing_error
|
def raise_routing_error
|
||||||
raise ActionController::RoutingError.new("No route matches #{options.inspect}")
|
raise ActionController::RoutingError.new("No route matches #{options.inspect}")
|
||||||
end
|
end
|
||||||
|
|
|
@ -209,8 +209,7 @@ module ActionView #:nodoc:
|
||||||
@_request = controller.request if controller.respond_to?(:request)
|
@_request = controller.request if controller.respond_to?(:request)
|
||||||
end
|
end
|
||||||
|
|
||||||
config = controller && controller.respond_to?(:config) ? controller.config : {}
|
@_config = controller && controller.respond_to?(:config) ? controller.config.inheritable_copy : {}
|
||||||
@_config = ActiveSupport::InheritableOptions.new(config)
|
|
||||||
|
|
||||||
@_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
|
@_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
|
||||||
@_virtual_path = nil
|
@_virtual_path = nil
|
||||||
|
|
|
@ -705,19 +705,29 @@ module ActionView
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def rewrite_extension?(source, dir, ext)
|
def rewrite_extension(source, dir, ext)
|
||||||
source_ext = File.extname(source)[1..-1]
|
source_ext = File.extname(source)
|
||||||
ext && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}"))))
|
|
||||||
|
if source_ext.empty?
|
||||||
|
"#{source}.#{ext}"
|
||||||
|
elsif ext != source_ext[1..-1]
|
||||||
|
with_ext = "#{source}.#{ext}"
|
||||||
|
with_ext if File.exist?(File.join(config.assets_dir, dir, with_ext))
|
||||||
|
end || source
|
||||||
end
|
end
|
||||||
|
|
||||||
def rewrite_host_and_protocol(source, has_request)
|
def rewrite_host_and_protocol(source, has_request)
|
||||||
host = compute_asset_host(source)
|
host = compute_asset_host(source)
|
||||||
if has_request && host.present? && !is_uri?(host)
|
if has_request && host && !is_uri?(host)
|
||||||
host = "#{controller.request.protocol}#{host}"
|
host = "#{controller.request.protocol}#{host}"
|
||||||
end
|
end
|
||||||
"#{host}#{source}"
|
"#{host}#{source}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def rewrite_relative_url_root(source, relative_url_root)
|
||||||
|
relative_url_root && !source.starts_with?("#{relative_url_root}/") ? "#{relative_url_root}#{source}" : source
|
||||||
|
end
|
||||||
|
|
||||||
# Add the the extension +ext+ if not present. Return full URLs otherwise untouched.
|
# Add the the extension +ext+ if not present. Return full URLs otherwise untouched.
|
||||||
# Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
|
# Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
|
||||||
# roots. Rewrite the asset path for cache-busting asset ids. Include
|
# roots. Rewrite the asset path for cache-busting asset ids. Include
|
||||||
|
@ -725,17 +735,15 @@ module ActionView
|
||||||
def compute_public_path(source, dir, ext = nil, include_host = true)
|
def compute_public_path(source, dir, ext = nil, include_host = true)
|
||||||
return source if is_uri?(source)
|
return source if is_uri?(source)
|
||||||
|
|
||||||
source += ".#{ext}" if rewrite_extension?(source, dir, ext)
|
source = rewrite_extension(source, dir, ext) if ext
|
||||||
source = "/#{dir}/#{source}" unless source[0] == ?/
|
source = "/#{dir}/#{source}" unless source[0] == ?/
|
||||||
if controller.respond_to?(:env) && controller.env["action_dispatch.asset_path"]
|
if controller.respond_to?(:env) && controller.env["action_dispatch.asset_path"]
|
||||||
source = rewrite_asset_path(source, controller.env["action_dispatch.asset_path"])
|
source = rewrite_asset_path(source, controller.env["action_dispatch.asset_path"])
|
||||||
end
|
end
|
||||||
source = rewrite_asset_path(source, config.asset_path)
|
source = rewrite_asset_path(source, config.asset_path)
|
||||||
|
|
||||||
has_request = controller.respond_to?(:request)
|
has_request = controller.respond_to?(:request)
|
||||||
if has_request && include_host && source !~ %r{^#{controller.config.relative_url_root}/}
|
source = rewrite_relative_url_root(source, controller.config.relative_url_root) if has_request && include_host
|
||||||
source = "#{controller.config.relative_url_root}#{source}"
|
|
||||||
end
|
|
||||||
source = rewrite_host_and_protocol(source, has_request) if include_host
|
source = rewrite_host_and_protocol(source, has_request) if include_host
|
||||||
|
|
||||||
source
|
source
|
||||||
|
@ -802,10 +810,10 @@ module ActionView
|
||||||
end
|
end
|
||||||
|
|
||||||
asset_id = rails_asset_id(source)
|
asset_id = rails_asset_id(source)
|
||||||
if asset_id.blank?
|
if asset_id.empty?
|
||||||
source
|
source
|
||||||
else
|
else
|
||||||
source + "?#{asset_id}"
|
"#{source}?#{asset_id}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ module ActionView
|
||||||
# # => javascript:history.back()
|
# # => javascript:history.back()
|
||||||
def url_for(options = {})
|
def url_for(options = {})
|
||||||
options ||= {}
|
options ||= {}
|
||||||
url = case options
|
case options
|
||||||
when String
|
when String
|
||||||
options
|
options
|
||||||
when Hash
|
when Hash
|
||||||
|
@ -106,8 +106,6 @@ module ActionView
|
||||||
else
|
else
|
||||||
polymorphic_path(options)
|
polymorphic_path(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
url
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a link tag of the given +name+ using a URL created by the set
|
# Creates a link tag of the given +name+ using a URL created by the set
|
||||||
|
@ -586,20 +584,24 @@ module ActionView
|
||||||
|
|
||||||
private
|
private
|
||||||
def convert_options_to_data_attributes(options, html_options)
|
def convert_options_to_data_attributes(options, html_options)
|
||||||
html_options = {} if html_options.nil?
|
if html_options.nil?
|
||||||
html_options = html_options.stringify_keys
|
link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
|
||||||
|
else
|
||||||
|
html_options = html_options.stringify_keys
|
||||||
|
html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
|
||||||
|
|
||||||
if (options.is_a?(Hash) && options.key?('remote') && options.delete('remote')) || (html_options.is_a?(Hash) && html_options.key?('remote') && html_options.delete('remote'))
|
confirm = html_options.delete('confirm')
|
||||||
html_options['data-remote'] = 'true'
|
method = html_options.delete('method')
|
||||||
|
|
||||||
|
add_confirm_to_attributes!(html_options, confirm) if confirm
|
||||||
|
add_method_to_attributes!(html_options, method) if method
|
||||||
|
|
||||||
|
html_options
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
confirm = html_options.delete("confirm")
|
def link_to_remote_options?(options)
|
||||||
method, href = html_options.delete("method"), html_options['href']
|
options.is_a?(Hash) && options.key?('remote') && options.delete('remote')
|
||||||
|
|
||||||
add_confirm_to_attributes!(html_options, confirm) if confirm
|
|
||||||
add_method_to_attributes!(html_options, method) if method
|
|
||||||
|
|
||||||
html_options
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_confirm_to_attributes!(html_options, confirm)
|
def add_confirm_to_attributes!(html_options, confirm)
|
||||||
|
|
|
@ -73,8 +73,10 @@ module ActiveModel
|
||||||
# Returns an ActiveModel::Name object for module. It can be
|
# Returns an ActiveModel::Name object for module. It can be
|
||||||
# used to retrieve all kinds of naming-related information.
|
# used to retrieve all kinds of naming-related information.
|
||||||
def model_name
|
def model_name
|
||||||
namespace = self.parents.detect { |n| n.respond_to?(:_railtie) }
|
@_model_name ||= begin
|
||||||
@_model_name ||= ActiveModel::Name.new(self, namespace)
|
namespace = self.parents.detect { |n| n.respond_to?(:_railtie) }
|
||||||
|
ActiveModel::Name.new(self, namespace)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the plural class name of a record or class. Examples:
|
# Returns the plural class name of a record or class. Examples:
|
||||||
|
|
|
@ -9,9 +9,29 @@ module ActiveSupport
|
||||||
module Configurable
|
module Configurable
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
class Configuration < ActiveSupport::InheritableOptions
|
||||||
|
def crystalize!
|
||||||
|
self.class.crystalize!(keys.reject {|key| respond_to?(key)})
|
||||||
|
end
|
||||||
|
|
||||||
|
# compiles reader methods so we don't have to go through method_missing
|
||||||
|
def self.crystalize!(keys)
|
||||||
|
keys.each do |key|
|
||||||
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||||
|
def #{key}; _get(#{key.inspect}); end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
def config
|
def config
|
||||||
@_config ||= ActiveSupport::InheritableOptions.new(superclass.respond_to?(:config) ? superclass.config : {})
|
@_config ||= if superclass.respond_to?(:config)
|
||||||
|
superclass.config.inheritable_copy
|
||||||
|
else
|
||||||
|
# create a new "anonymous" class that will host the compiled reader methods
|
||||||
|
Class.new(Configuration).new
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def configure
|
def configure
|
||||||
|
@ -48,7 +68,7 @@ module ActiveSupport
|
||||||
# user.config.level # => 1
|
# user.config.level # => 1
|
||||||
#
|
#
|
||||||
def config
|
def config
|
||||||
@_config ||= ActiveSupport::InheritableOptions.new(self.class.config)
|
@_config ||= self.class.config.inheritable_copy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -72,11 +72,20 @@ class Class
|
||||||
remove_possible_method(:#{name})
|
remove_possible_method(:#{name})
|
||||||
define_method(:#{name}) { val }
|
define_method(:#{name}) { val }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if singleton_class?
|
||||||
|
class_eval do
|
||||||
|
remove_possible_method(:#{name})
|
||||||
|
def #{name}
|
||||||
|
defined?(@#{name}) ? @#{name} : singleton_class.#{name}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
val
|
val
|
||||||
end
|
end
|
||||||
|
|
||||||
def #{name}
|
def #{name}
|
||||||
defined?(@#{name}) ? @#{name} : singleton_class.#{name}
|
defined?(@#{name}) ? @#{name} : self.class.#{name}
|
||||||
end
|
end
|
||||||
|
|
||||||
def #{name}?
|
def #{name}?
|
||||||
|
@ -87,4 +96,15 @@ class Class
|
||||||
attr_writer name if instance_writer
|
attr_writer name if instance_writer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def singleton_class?
|
||||||
|
# in case somebody is crazy enough to overwrite allocate
|
||||||
|
allocate = Class.instance_method(:allocate)
|
||||||
|
# object.class always points to a real (non-singleton) class
|
||||||
|
allocate.bind(self).call.class != self
|
||||||
|
rescue TypeError
|
||||||
|
# MRI/YARV/JRuby all disallow creating new instances of a singleton class
|
||||||
|
true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,11 +35,13 @@ class Hash
|
||||||
# as keys, this will fail.
|
# as keys, this will fail.
|
||||||
#
|
#
|
||||||
# ==== Examples
|
# ==== Examples
|
||||||
# { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
|
# { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
|
||||||
# { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
|
# { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key: name"
|
||||||
# { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
# { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
||||||
def assert_valid_keys(*valid_keys)
|
def assert_valid_keys(*valid_keys)
|
||||||
unknown_keys = keys - [valid_keys].flatten
|
valid_keys.flatten!
|
||||||
raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
|
each_key do |k|
|
||||||
|
raise(ArgumentError, "Unknown key: #{k}") unless valid_keys.include?(k)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
class Module
|
class Module
|
||||||
# Declares an attribute reader backed by an internally-named instance variable.
|
# Declares an attribute reader backed by an internally-named instance variable.
|
||||||
def attr_internal_reader(*attrs)
|
def attr_internal_reader(*attrs)
|
||||||
attrs.each do |attr|
|
attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
|
||||||
module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end", __FILE__, __LINE__
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Declares an attribute writer backed by an internally-named instance variable.
|
# Declares an attribute writer backed by an internally-named instance variable.
|
||||||
def attr_internal_writer(*attrs)
|
def attr_internal_writer(*attrs)
|
||||||
attrs.each do |attr|
|
attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
|
||||||
module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end", __FILE__, __LINE__
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Declares an attribute reader and writer backed by an internally-named instance
|
# Declares an attribute reader and writer backed by an internally-named instance
|
||||||
|
@ -29,4 +25,15 @@ class Module
|
||||||
def attr_internal_ivar_name(attr)
|
def attr_internal_ivar_name(attr)
|
||||||
Module.attr_internal_naming_format % attr
|
Module.attr_internal_naming_format % attr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def attr_internal_define(attr_name, type)
|
||||||
|
internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '')
|
||||||
|
class_eval do # class_eval is necessary on 1.9 or else the methods a made private
|
||||||
|
# use native attr_* methods as they are faster on some Ruby implementations
|
||||||
|
send("attr_#{type}", internal_name)
|
||||||
|
end
|
||||||
|
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|
||||||
|
alias_method attr_name, internal_name
|
||||||
|
remove_method internal_name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,6 +18,9 @@ require 'active_support/ordered_hash'
|
||||||
#
|
#
|
||||||
module ActiveSupport #:nodoc:
|
module ActiveSupport #:nodoc:
|
||||||
class OrderedOptions < OrderedHash
|
class OrderedOptions < OrderedHash
|
||||||
|
alias_method :_get, :[] # preserve the original #[] method
|
||||||
|
protected :_get # make it protected
|
||||||
|
|
||||||
def []=(key, value)
|
def []=(key, value)
|
||||||
super(key.to_sym, value)
|
super(key.to_sym, value)
|
||||||
end
|
end
|
||||||
|
@ -36,8 +39,19 @@ module ActiveSupport #:nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
class InheritableOptions < OrderedOptions
|
class InheritableOptions < OrderedOptions
|
||||||
def initialize(parent)
|
def initialize(parent = nil)
|
||||||
super() { |h,k| parent[k] }
|
if parent.kind_of?(OrderedOptions)
|
||||||
|
# use the faster _get when dealing with OrderedOptions
|
||||||
|
super() { |h,k| parent._get(k) }
|
||||||
|
elsif parent
|
||||||
|
super() { |h,k| parent[k] }
|
||||||
|
else
|
||||||
|
super()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def inheritable_copy
|
||||||
|
self.class.new(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,4 +39,22 @@ class ConfigurableActiveSupport < ActiveSupport::TestCase
|
||||||
assert_equal :baz, instance.config.foo
|
assert_equal :baz, instance.config.foo
|
||||||
assert_equal :bar, Parent.config.foo
|
assert_equal :bar, Parent.config.foo
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "configuration is crystalizeable" do
|
||||||
|
parent = Class.new { include ActiveSupport::Configurable }
|
||||||
|
child = Class.new(parent)
|
||||||
|
|
||||||
|
parent.config.bar = :foo
|
||||||
|
assert !parent.config.respond_to?(:bar)
|
||||||
|
assert !child.config.respond_to?(:bar)
|
||||||
|
assert !child.new.config.respond_to?(:bar)
|
||||||
|
|
||||||
|
parent.config.crystalize!
|
||||||
|
assert_equal :foo, parent.config.bar
|
||||||
|
assert_equal :foo, child.new.config.bar
|
||||||
|
|
||||||
|
assert_respond_to parent.config, :bar
|
||||||
|
assert_respond_to child.config, :bar
|
||||||
|
assert_respond_to child.new.config, :bar
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -282,7 +282,7 @@ class HashExtTest < Test::Unit::TestCase
|
||||||
{ :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny)
|
{ :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_raise(ArgumentError, "Unknown key(s): failore") do
|
assert_raise(ArgumentError, "Unknown key: failore") do
|
||||||
{ :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ])
|
{ :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ])
|
||||||
{ :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny)
|
{ :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue