Skip to content

Commit

Permalink
Define attribute query methods to avoid method_missing calls. Closes #…
Browse files Browse the repository at this point in the history
…3677.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3679 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
jeremy committed Feb 27, 2006
1 parent 660952e commit 1a06d32
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 7 deletions.
2 changes: 2 additions & 0 deletions activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*

* Define attribute query methods to avoid method_missing calls. #3677 [jonathan@bluewire.net.nz]

* ActiveRecord::Base.remove_connection explicitly closes database connections and doesn't corrupt the connection cache. Introducing the disconnect! instance method for the PostgreSQL, MySQL, and SQL Server adapters; implementations for the others are welcome. #3591 [Simon Stapleton, Tom Ward]

* Added support for nested scopes #3407 [anna@wota.jp]. Examples:
Expand Down
13 changes: 8 additions & 5 deletions activerecord/lib/active_record/base.rb
Expand Up @@ -1544,19 +1544,19 @@ def ensure_proper_type
# table with a master_id foreign key can instantiate master through Client#master.
def method_missing(method_id, *args, &block)
method_name = method_id.to_s
if @attributes.include?(method_name)
if @attributes.include?(method_name) or
(md = /\?$/.match(method_name) and
@attributes.include?(method_name = md.pre_match))
define_read_methods if self.class.read_methods.empty? && self.class.generate_read_methods
read_attribute(method_name)
md ? query_attribute(method_name) : read_attribute(method_name)
elsif self.class.primary_key.to_s == method_name
id
elsif md = /(=|\?|_before_type_cast)$/.match(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
Expand Down Expand Up @@ -1610,12 +1610,15 @@ def define_read_method(symbol, attr_name, column)
unless attr_name.to_s == self.class.primary_key.to_s
access_code = access_code.insert(0, "raise NoMethodError, 'missing attribute: #{attr_name}', caller unless @attributes.has_key?('#{attr_name}'); ")
self.class.read_methods << attr_name
self.class.read_methods << "#{attr_name}?"
end

begin
self.class.class_eval("def #{symbol}; #{access_code}; end")
self.class.class_eval("def #{symbol}?; query_attribute('#{attr_name}'); end")
rescue SyntaxError => err
self.class.read_methods.delete(attr_name)
self.class.read_methods.delete("#{attr_name}?")
if logger
logger.warn "Exception occured during reader method compilation."
logger.warn "Maybe #{attr_name} is not a valid Ruby identifier?"
Expand Down
5 changes: 3 additions & 2 deletions activerecord/test/base_test.rb
Expand Up @@ -1163,7 +1163,8 @@ def test_base_class

private
def assert_readers(model, exceptions)
expected_readers = model.column_names - (model.serialized_attributes.keys + exceptions + ['id'])
assert_equal expected_readers.sort, model.read_methods.to_a.sort
expected_readers = Set.new(model.column_names - (model.serialized_attributes.keys + exceptions + ['id']))
expected_readers += expected_readers.map { |col| "#{col}?" }
assert_equal expected_readers, model.read_methods
end
end

0 comments on commit 1a06d32

Please sign in to comment.