aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/dynamic_matchers.rb
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2012-05-04 14:30:57 +0100
committerJon Leighton <j@jonathanleighton.com>2012-05-04 14:31:19 +0100
commit510cf0ad93f07e9285178c8b7ba7d4d68c139fec (patch)
tree151a0fe3bc9c050c943c17c6bc0f82b717a30dcc /activerecord/lib/active_record/dynamic_matchers.rb
parentffad3600ea01cda457b447fafd4d38907f4d0bfb (diff)
downloadrails-510cf0ad93f07e9285178c8b7ba7d4d68c139fec.tar.gz
rails-510cf0ad93f07e9285178c8b7ba7d4d68c139fec.tar.bz2
rails-510cf0ad93f07e9285178c8b7ba7d4d68c139fec.zip
extract deprecated dynamic methods
Diffstat (limited to 'activerecord/lib/active_record/dynamic_matchers.rb')
-rw-r--r--activerecord/lib/active_record/dynamic_matchers.rb178
1 files changed, 38 insertions, 140 deletions
diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb
index 8726442d0b..e278e62ce7 100644
--- a/activerecord/lib/active_record/dynamic_matchers.rb
+++ b/activerecord/lib/active_record/dynamic_matchers.rb
@@ -1,5 +1,10 @@
module ActiveRecord
- module DynamicMatchers
+ module DynamicMatchers #:nodoc:
+ # This code in this file seems to have a lot of indirection, but the indirection
+ # is there to provide extension points for the active_record_deprecated_finders
+ # gem. When we stop supporting active_record_deprecated_finders (from Rails 5),
+ # then we can remove the indirection.
+
def respond_to?(name, include_private = false)
match = Method.match(self, name)
match && match.valid? || super
@@ -7,15 +12,6 @@ module ActiveRecord
private
- # Enables dynamic finders like <tt>User.find_by_user_name(user_name)</tt> and
- # <tt>User.scoped_by_user_name(user_name). Refer to Dynamic attribute-based finders
- # section at the top of this file for more detailed information.
- #
- # It's even possible to use all the additional parameters to +find+. For example, the
- # full interface for +find_all_by_amount+ is actually <tt>find_all_by_amount(amount, options)</tt>.
- #
- # Each dynamic finder using <tt>scoped_by_*</tt> is also defined in the class after it
- # is first invoked, so that future attempts to use it do not run through method_missing.
def method_missing(name, *arguments, &block)
match = Method.match(self, name)
@@ -28,28 +24,27 @@ module ActiveRecord
end
class Method
- def self.match(model, name)
- klass = klasses.find { |k| name =~ k.pattern }
- klass.new(model, name) if klass
- end
+ @matchers = []
- def self.klasses
- [
- FindBy, FindAllBy, FindLastBy, FindByBang, ScopedBy,
- FindOrInitializeBy, FindOrCreateBy, FindOrCreateByBang
- ]
- end
+ class << self
+ attr_reader :matchers
- def self.pattern
- /^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/
- end
+ def match(model, name)
+ klass = matchers.find { |k| name =~ k.pattern }
+ klass.new(model, name) if klass
+ end
- def self.prefix
- raise NotImplementedError
- end
+ def pattern
+ /^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/
+ end
- def self.suffix
- ''
+ def prefix
+ raise NotImplementedError
+ end
+
+ def suffix
+ ''
+ end
end
attr_reader :model, :name, :attribute_names
@@ -77,20 +72,20 @@ module ActiveRecord
end
end
- class Finder < Method
+ module Finder
+ # Extended in active_record_deprecated_finders
def body
- <<-CODE
- result = #{result}
- result && block_given? ? yield(result) : result
- CODE
+ result
end
+ # Extended in active_record_deprecated_finders
def result
- "scoped.apply_finder_options(options).#{finder}(#{attributes_hash})"
+ "#{finder}(#{attributes_hash})"
end
+ # Extended in active_record_deprecated_finders
def signature
- attribute_names.join(', ') + ", options = {}"
+ attribute_names.join(', ')
end
def attributes_hash
@@ -102,7 +97,10 @@ module ActiveRecord
end
end
- class FindBy < Finder
+ class FindBy < Method
+ Method.matchers << self
+ include Finder
+
def self.prefix
"find_by"
end
@@ -112,7 +110,10 @@ module ActiveRecord
end
end
- class FindByBang < Finder
+ class FindByBang < Method
+ Method.matchers << self
+ include Finder
+
def self.prefix
"find_by"
end
@@ -125,108 +126,5 @@ module ActiveRecord
"find_by!"
end
end
-
- class FindAllBy < Finder
- def self.prefix
- "find_all_by"
- end
-
- def finder
- "where"
- end
-
- def result
- "#{super}.to_a"
- end
- end
-
- class FindLastBy < Finder
- def self.prefix
- "find_last_by"
- end
-
- def finder
- "where"
- end
-
- def result
- "#{super}.last"
- end
- end
-
- class ScopedBy < Finder
- def self.prefix
- "scoped_by"
- end
-
- def body
- "where(#{attributes_hash})"
- end
- end
-
- class Instantiator < Method
- # This is nasty, but it doesn't matter because it will be deprecated.
- def self.dispatch(klass, attribute_names, instantiator, args, block)
- if args.length == 1 && args.first.is_a?(Hash)
- attributes = args.first.stringify_keys
- conditions = attributes.slice(*attribute_names)
- rest = [attributes.except(*attribute_names)]
- else
- raise ArgumentError, "too few arguments" unless args.length >= attribute_names.length
-
- conditions = Hash[attribute_names.map.with_index { |n, i| [n, args[i]] }]
- rest = args.drop(attribute_names.length)
- end
-
- klass.where(conditions).first ||
- klass.create_with(conditions).send(instantiator, *rest, &block)
- end
-
- def signature
- "*args, &block"
- end
-
- def body
- "#{self.class}.dispatch(self, #{attribute_names.inspect}, #{instantiator.inspect}, args, block)"
- end
-
- def instantiator
- raise NotImplementedError
- end
- end
-
- class FindOrInitializeBy < Instantiator
- def self.prefix
- "find_or_initialize_by"
- end
-
- def instantiator
- "new"
- end
- end
-
- class FindOrCreateBy < Instantiator
- def self.prefix
- "find_or_create_by"
- end
-
- def instantiator
- "create"
- end
- end
-
- class FindOrCreateByBang < Instantiator
- def self.prefix
- "find_or_create_by"
- end
-
- def self.suffix
- "!"
- end
-
- def instantiator
- "create!"
- end
- end
end
end