mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
optimize method_missing for common case (read_attribute). minor perf tweaks git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1631 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
5bc1e39b35
commit
81737fc0dd
1 changed files with 59 additions and 64 deletions
|
@ -606,9 +606,9 @@ module ActiveRecord #:nodoc:
|
|||
# Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
|
||||
def class_name(table_name = table_name) # :nodoc:
|
||||
# remove any prefix and/or suffix from the table name
|
||||
class_name = Inflector.camelize(table_name[table_name_prefix.length..-(table_name_suffix.length + 1)])
|
||||
class_name = Inflector.singularize(class_name) if pluralize_table_names
|
||||
return class_name
|
||||
class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize
|
||||
class_name = class_name.singularize if pluralize_table_names
|
||||
class_name
|
||||
end
|
||||
|
||||
# Returns an array of column objects for the table associated with this class.
|
||||
|
@ -661,7 +661,7 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
|
||||
def descends_from_active_record? # :nodoc:
|
||||
superclass == Base || !columns_hash.has_key?(inheritance_column)
|
||||
superclass == Base || !columns_hash.include?(inheritance_column)
|
||||
end
|
||||
|
||||
def quote(object) #:nodoc:
|
||||
|
@ -673,7 +673,7 @@ module ActiveRecord #:nodoc:
|
|||
connection.quote(object)
|
||||
end
|
||||
|
||||
# Used to aggregate logging and benchmark, so you can measure and represent multiple statements in a single block.
|
||||
# Log and benchmark multiple statements in a single block.
|
||||
# Usage (hides all the SQL calls for the individual actions and calculates total runtime for them all):
|
||||
#
|
||||
# Project.benchmark("Creating project") do
|
||||
|
@ -683,19 +683,17 @@ module ActiveRecord #:nodoc:
|
|||
# end
|
||||
def benchmark(title)
|
||||
result = nil
|
||||
bm = Benchmark.measure { result = silence { yield } }
|
||||
logger.info "#{title} (#{sprintf("%f", bm.real)})" if logger
|
||||
seconds = Benchmark.realtime { result = silence { yield } }
|
||||
logger.info "#{title} (#{sprintf("%f", seconds)})" if logger
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
# Silences the logger for the duration of the block.
|
||||
def silence
|
||||
result = nil
|
||||
old_logger_level = logger.level if logger
|
||||
logger.level = Logger::ERROR if logger
|
||||
result = yield
|
||||
old_logger_level, logger.level = logger.level, Logger::ERROR if logger
|
||||
yield
|
||||
ensure
|
||||
logger.level = old_logger_level if logger
|
||||
return result
|
||||
end
|
||||
|
||||
# Overwrite the default class equality method to provide support for association proxies.
|
||||
|
@ -707,30 +705,27 @@ module ActiveRecord #:nodoc:
|
|||
# Finder methods must instantiate through this method to work with the single-table inheritance model
|
||||
# that makes it possible to create objects of different types from the same table.
|
||||
def instantiate(record)
|
||||
require_association_class(record[inheritance_column])
|
||||
subclass_name = record[inheritance_column]
|
||||
require_association_class(subclass_name)
|
||||
|
||||
begin
|
||||
object = record_with_type?(record) ? compute_type(record[inheritance_column]).allocate : allocate
|
||||
rescue NameError
|
||||
raise(
|
||||
SubclassNotFound,
|
||||
"The single-table inheritance mechanism failed to locate the subclass: '#{record[inheritance_column]}'. " +
|
||||
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
|
||||
"Please rename this column if you didn't intend it to be used for storing the inheritance class " +
|
||||
"or overwrite #{self.to_s}.inheritance_column to use another column for that information."
|
||||
)
|
||||
object = if subclass_name.blank?
|
||||
allocate
|
||||
else
|
||||
begin
|
||||
compute_type(subclass_name).allocate
|
||||
rescue NameError
|
||||
raise SubclassNotFound,
|
||||
"The single-table inheritance mechanism failed to locate the subclass: '#{record[inheritance_column]}'. " +
|
||||
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
|
||||
"Please rename this column if you didn't intend it to be used for storing the inheritance class " +
|
||||
"or overwrite #{self.to_s}.inheritance_column to use another column for that information."
|
||||
end
|
||||
end
|
||||
|
||||
object.instance_variable_set("@attributes", record)
|
||||
return object
|
||||
object
|
||||
end
|
||||
|
||||
# Returns true if the +record+ has a single table inheritance column and is using it.
|
||||
def record_with_type?(record)
|
||||
record.include?(inheritance_column) && !record[inheritance_column].nil? &&
|
||||
!record[inheritance_column].empty?
|
||||
end
|
||||
|
||||
|
||||
# Returns the name of the type of the record using the current module as a prefix. So descendents of
|
||||
# MyApp::Business::Account would be appear as "MyApp::Business::AccountSubclass".
|
||||
def type_name_with_module(type_name)
|
||||
|
@ -781,15 +776,16 @@ module ActiveRecord #:nodoc:
|
|||
def method_missing(method_id, *arguments)
|
||||
method_name = method_id.id2name
|
||||
|
||||
if method_name =~ /find_(all_by|by)_([_a-zA-Z]\w*)/
|
||||
finder, attributes = ($1 == "all_by" ? :all : :first), $2.split("_and_")
|
||||
attributes.each { |attr_name| super unless column_methods_hash[attr_name.intern] }
|
||||
if md = /find_(all_by|by)_([_a-zA-Z]\w*)/.match(method_id.to_s)
|
||||
finder = md.captures.first == 'all_by' ? :all : :first
|
||||
attributes = md.captures.last.split('_and_')
|
||||
attributes.each { |attr_name| super unless column_methods_hash.include?(attr_name.to_sym) }
|
||||
|
||||
attr_index = -1
|
||||
conditions = attributes.collect { |attr_name| attr_index += 1; "#{attr_name} #{attribute_condition(arguments[attr_index])} " }.join(" AND ")
|
||||
|
||||
|
||||
if arguments[attributes.length].is_a?(Hash)
|
||||
find(finder, { :conditions => [conditions, *arguments[0...attributes.length]]}.merge(arguments[attributes.length]))
|
||||
find(finder, { :conditions => [conditions, *arguments[0...attributes.length]] }.update(arguments[attributes.length]))
|
||||
else
|
||||
# deprecated API
|
||||
send("find_#{finder}", [conditions, *arguments[0...attributes.length]], *arguments[attributes.length..-1])
|
||||
|
@ -885,7 +881,7 @@ module ActiveRecord #:nodoc:
|
|||
raise_if_bind_arity_mismatch(statement, statement.scan(/:(\w+)/).uniq.size, bind_vars.size)
|
||||
statement.gsub(/:(\w+)/) do
|
||||
match = $1.to_sym
|
||||
if bind_vars.has_key?(match)
|
||||
if bind_vars.include?(match)
|
||||
quote_bound_value(bind_vars[match])
|
||||
else
|
||||
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
||||
|
@ -945,9 +941,9 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
|
||||
def quoted_id #:nodoc:
|
||||
quote(id, self.class.columns_hash[self.class.primary_key])
|
||||
quote(id, column_for_attribute(self.class.primary_key))
|
||||
end
|
||||
|
||||
|
||||
# Sets the primary ID.
|
||||
def id=(value)
|
||||
write_attribute(self.class.primary_key, value)
|
||||
|
@ -1181,39 +1177,41 @@ module ActiveRecord #:nodoc:
|
|||
#
|
||||
# It's also possible to instantiate related objects, so a Client class belonging to the clients
|
||||
# table with a master_id foreign key can instantiate master through Client#master.
|
||||
def method_missing(method_id, *arguments)
|
||||
method_name = method_id.id2name
|
||||
|
||||
if method_name =~ read_method? && @attributes.include?($1)
|
||||
return read_attribute($1)
|
||||
elsif method_name =~ read_untyped_method? && @attributes.include?($1)
|
||||
return read_attribute_before_type_cast($1)
|
||||
elsif method_name =~ write_method? && @attributes.include?($1)
|
||||
write_attribute($1, arguments[0])
|
||||
elsif method_name =~ query_method? && @attributes.include?($1)
|
||||
return query_attribute($1)
|
||||
def method_missing(method_id, *args, &block)
|
||||
method_name = method_id.to_s
|
||||
if @attributes.include?(method_name)
|
||||
read_attribute(method_name)
|
||||
elsif md = /(=|\?|_before_type_cast)$/.match(method_name)
|
||||
attribute_name, method_type = md.pre_match, md.to_s
|
||||
if @attributes.include?(attribute_name)
|
||||
case method_type
|
||||
when '='
|
||||
write_attribute(attribute_name, args.first)
|
||||
when '?'
|
||||
query_attribute(attribute_name)
|
||||
when '_before_type_cast'
|
||||
read_attribute_before_type_cast(attribute_name)
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def read_method?() /^([a-zA-Z][-_\w]*)[^=?]*$/ end
|
||||
def read_untyped_method?() /^([a-zA-Z][-_\w]*)_before_type_cast$/ end
|
||||
def write_method?() /^([a-zA-Z][-_\w]*)=.*$/ end
|
||||
def query_method?() /^([a-zA-Z][-_\w]*)\?$/ end
|
||||
|
||||
# Returns the value of attribute identified by <tt>attr_name</tt> after it has been type cast (for example,
|
||||
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
|
||||
def read_attribute(attr_name)
|
||||
if @attributes.keys.include? attr_name
|
||||
if value = @attributes[attr_name]
|
||||
if column = column_for_attribute(attr_name)
|
||||
if unserializable_attribute?(attr_name, column)
|
||||
unserialize_attribute(attr_name)
|
||||
else
|
||||
column.type_cast(@attributes[attr_name])
|
||||
column.type_cast(value)
|
||||
end
|
||||
else
|
||||
@attributes[attr_name]
|
||||
value
|
||||
end
|
||||
else
|
||||
nil
|
||||
|
@ -1238,11 +1236,8 @@ module ActiveRecord #:nodoc:
|
|||
if unserialized_object.is_a?(self.class.serialized_attributes[attr_name])
|
||||
@attributes[attr_name] = unserialized_object
|
||||
else
|
||||
raise(
|
||||
SerializationTypeMismatch,
|
||||
"#{attr_name} was supposed to be a #{self.class.serialized_attributes[attr_name]}, " +
|
||||
"but was a #{unserialized_object.class.to_s}"
|
||||
)
|
||||
raise SerializationTypeMismatch,
|
||||
"#{attr_name} was supposed to be a #{self.class.serialized_attributes[attr_name]}, but was a #{unserialized_object.class.to_s}"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue