mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
extract deprecated dynamic methods
This commit is contained in:
parent
ffad3600ea
commit
510cf0ad93
2 changed files with 40 additions and 142 deletions
|
@ -1,5 +1,10 @@
|
||||||
module ActiveRecord
|
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)
|
def respond_to?(name, include_private = false)
|
||||||
match = Method.match(self, name)
|
match = Method.match(self, name)
|
||||||
match && match.valid? || super
|
match && match.valid? || super
|
||||||
|
@ -7,15 +12,6 @@ module ActiveRecord
|
||||||
|
|
||||||
private
|
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)
|
def method_missing(name, *arguments, &block)
|
||||||
match = Method.match(self, name)
|
match = Method.match(self, name)
|
||||||
|
|
||||||
|
@ -28,28 +24,27 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
class Method
|
class Method
|
||||||
def self.match(model, name)
|
@matchers = []
|
||||||
klass = klasses.find { |k| name =~ k.pattern }
|
|
||||||
klass.new(model, name) if klass
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.klasses
|
class << self
|
||||||
[
|
attr_reader :matchers
|
||||||
FindBy, FindAllBy, FindLastBy, FindByBang, ScopedBy,
|
|
||||||
FindOrInitializeBy, FindOrCreateBy, FindOrCreateByBang
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.pattern
|
def match(model, name)
|
||||||
/^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/
|
klass = matchers.find { |k| name =~ k.pattern }
|
||||||
end
|
klass.new(model, name) if klass
|
||||||
|
end
|
||||||
|
|
||||||
def self.prefix
|
def pattern
|
||||||
raise NotImplementedError
|
/^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.suffix
|
def prefix
|
||||||
''
|
raise NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
|
def suffix
|
||||||
|
''
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :model, :name, :attribute_names
|
attr_reader :model, :name, :attribute_names
|
||||||
|
@ -77,20 +72,20 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Finder < Method
|
module Finder
|
||||||
|
# Extended in active_record_deprecated_finders
|
||||||
def body
|
def body
|
||||||
<<-CODE
|
result
|
||||||
result = #{result}
|
|
||||||
result && block_given? ? yield(result) : result
|
|
||||||
CODE
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Extended in active_record_deprecated_finders
|
||||||
def result
|
def result
|
||||||
"scoped.apply_finder_options(options).#{finder}(#{attributes_hash})"
|
"#{finder}(#{attributes_hash})"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Extended in active_record_deprecated_finders
|
||||||
def signature
|
def signature
|
||||||
attribute_names.join(', ') + ", options = {}"
|
attribute_names.join(', ')
|
||||||
end
|
end
|
||||||
|
|
||||||
def attributes_hash
|
def attributes_hash
|
||||||
|
@ -102,7 +97,10 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class FindBy < Finder
|
class FindBy < Method
|
||||||
|
Method.matchers << self
|
||||||
|
include Finder
|
||||||
|
|
||||||
def self.prefix
|
def self.prefix
|
||||||
"find_by"
|
"find_by"
|
||||||
end
|
end
|
||||||
|
@ -112,7 +110,10 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class FindByBang < Finder
|
class FindByBang < Method
|
||||||
|
Method.matchers << self
|
||||||
|
include Finder
|
||||||
|
|
||||||
def self.prefix
|
def self.prefix
|
||||||
"find_by"
|
"find_by"
|
||||||
end
|
end
|
||||||
|
@ -125,108 +126,5 @@ module ActiveRecord
|
||||||
"find_by!"
|
"find_by!"
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -442,11 +442,11 @@ end
|
||||||
|
|
||||||
class DynamicScopeMatchTest < ActiveRecord::TestCase
|
class DynamicScopeMatchTest < ActiveRecord::TestCase
|
||||||
def test_scoped_by_no_match
|
def test_scoped_by_no_match
|
||||||
assert_nil ActiveRecord::DynamicMatchers::ScopedBy.match(nil, "not_scoped_at_all")
|
assert_nil ActiveRecord::DynamicMatchers::Method.match(nil, "not_scoped_at_all")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_scoped_by
|
def test_scoped_by
|
||||||
match = ActiveRecord::DynamicMatchers::ScopedBy.match(nil, "scoped_by_age_and_sex_and_location")
|
match = ActiveRecord::DynamicMatchers::Method.match(nil, "scoped_by_age_and_sex_and_location")
|
||||||
assert_not_nil match
|
assert_not_nil match
|
||||||
assert_equal %w(age sex location), match.attribute_names
|
assert_equal %w(age sex location), match.attribute_names
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue