Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

extract deprecated dynamic methods

  • Loading branch information...
commit 510cf0ad93f07e9285178c8b7ba7d4d68c139fec 1 parent ffad360
Jon Leighton jonleighton authored
178 activerecord/lib/active_record/dynamic_matchers.rb
... ... @@ -1,5 +1,10 @@
1 1 module ActiveRecord
2   - module DynamicMatchers
  2 + module DynamicMatchers #:nodoc:
  3 + # This code in this file seems to have a lot of indirection, but the indirection
  4 + # is there to provide extension points for the active_record_deprecated_finders
  5 + # gem. When we stop supporting active_record_deprecated_finders (from Rails 5),
  6 + # then we can remove the indirection.
  7 +
3 8 def respond_to?(name, include_private = false)
4 9 match = Method.match(self, name)
5 10 match && match.valid? || super
@@ -7,15 +12,6 @@ def respond_to?(name, include_private = false)
7 12
8 13 private
9 14
10   - # Enables dynamic finders like <tt>User.find_by_user_name(user_name)</tt> and
11   - # <tt>User.scoped_by_user_name(user_name). Refer to Dynamic attribute-based finders
12   - # section at the top of this file for more detailed information.
13   - #
14   - # It's even possible to use all the additional parameters to +find+. For example, the
15   - # full interface for +find_all_by_amount+ is actually <tt>find_all_by_amount(amount, options)</tt>.
16   - #
17   - # Each dynamic finder using <tt>scoped_by_*</tt> is also defined in the class after it
18   - # is first invoked, so that future attempts to use it do not run through method_missing.
19 15 def method_missing(name, *arguments, &block)
20 16 match = Method.match(self, name)
21 17
@@ -28,28 +24,27 @@ def method_missing(name, *arguments, &block)
28 24 end
29 25
30 26 class Method
31   - def self.match(model, name)
32   - klass = klasses.find { |k| name =~ k.pattern }
33   - klass.new(model, name) if klass
34   - end
  27 + @matchers = []
35 28
36   - def self.klasses
37   - [
38   - FindBy, FindAllBy, FindLastBy, FindByBang, ScopedBy,
39   - FindOrInitializeBy, FindOrCreateBy, FindOrCreateByBang
40   - ]
41   - end
  29 + class << self
  30 + attr_reader :matchers
42 31
43   - def self.pattern
44   - /^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/
45   - end
  32 + def match(model, name)
  33 + klass = matchers.find { |k| name =~ k.pattern }
  34 + klass.new(model, name) if klass
  35 + end
46 36
47   - def self.prefix
48   - raise NotImplementedError
49   - end
  37 + def pattern
  38 + /^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/
  39 + end
50 40
51   - def self.suffix
52   - ''
  41 + def prefix
  42 + raise NotImplementedError
  43 + end
  44 +
  45 + def suffix
  46 + ''
  47 + end
53 48 end
54 49
55 50 attr_reader :model, :name, :attribute_names
@@ -77,20 +72,20 @@ def body
77 72 end
78 73 end
79 74
80   - class Finder < Method
  75 + module Finder
  76 + # Extended in active_record_deprecated_finders
81 77 def body
82   - <<-CODE
83   - result = #{result}
84   - result && block_given? ? yield(result) : result
85   - CODE
  78 + result
86 79 end
87 80
  81 + # Extended in active_record_deprecated_finders
88 82 def result
89   - "scoped.apply_finder_options(options).#{finder}(#{attributes_hash})"
  83 + "#{finder}(#{attributes_hash})"
90 84 end
91 85
  86 + # Extended in active_record_deprecated_finders
92 87 def signature
93   - attribute_names.join(', ') + ", options = {}"
  88 + attribute_names.join(', ')
94 89 end
95 90
96 91 def attributes_hash
@@ -102,7 +97,10 @@ def finder
102 97 end
103 98 end
104 99
105   - class FindBy < Finder
  100 + class FindBy < Method
  101 + Method.matchers << self
  102 + include Finder
  103 +
106 104 def self.prefix
107 105 "find_by"
108 106 end
@@ -112,7 +110,10 @@ def finder
112 110 end
113 111 end
114 112
115   - class FindByBang < Finder
  113 + class FindByBang < Method
  114 + Method.matchers << self
  115 + include Finder
  116 +
116 117 def self.prefix
117 118 "find_by"
118 119 end
@@ -125,108 +126,5 @@ def finder
125 126 "find_by!"
126 127 end
127 128 end
128   -
129   - class FindAllBy < Finder
130   - def self.prefix
131   - "find_all_by"
132   - end
133   -
134   - def finder
135   - "where"
136   - end
137   -
138   - def result
139   - "#{super}.to_a"
140   - end
141   - end
142   -
143   - class FindLastBy < Finder
144   - def self.prefix
145   - "find_last_by"
146   - end
147   -
148   - def finder
149   - "where"
150   - end
151   -
152   - def result
153   - "#{super}.last"
154   - end
155   - end
156   -
157   - class ScopedBy < Finder
158   - def self.prefix
159   - "scoped_by"
160   - end
161   -
162   - def body
163   - "where(#{attributes_hash})"
164   - end
165   - end
166   -
167   - class Instantiator < Method
168   - # This is nasty, but it doesn't matter because it will be deprecated.
169   - def self.dispatch(klass, attribute_names, instantiator, args, block)
170   - if args.length == 1 && args.first.is_a?(Hash)
171   - attributes = args.first.stringify_keys
172   - conditions = attributes.slice(*attribute_names)
173   - rest = [attributes.except(*attribute_names)]
174   - else
175   - raise ArgumentError, "too few arguments" unless args.length >= attribute_names.length
176   -
177   - conditions = Hash[attribute_names.map.with_index { |n, i| [n, args[i]] }]
178   - rest = args.drop(attribute_names.length)
179   - end
180   -
181   - klass.where(conditions).first ||
182   - klass.create_with(conditions).send(instantiator, *rest, &block)
183   - end
184   -
185   - def signature
186   - "*args, &block"
187   - end
188   -
189   - def body
190   - "#{self.class}.dispatch(self, #{attribute_names.inspect}, #{instantiator.inspect}, args, block)"
191   - end
192   -
193   - def instantiator
194   - raise NotImplementedError
195   - end
196   - end
197   -
198   - class FindOrInitializeBy < Instantiator
199   - def self.prefix
200   - "find_or_initialize_by"
201   - end
202   -
203   - def instantiator
204   - "new"
205   - end
206   - end
207   -
208   - class FindOrCreateBy < Instantiator
209   - def self.prefix
210   - "find_or_create_by"
211   - end
212   -
213   - def instantiator
214   - "create"
215   - end
216   - end
217   -
218   - class FindOrCreateByBang < Instantiator
219   - def self.prefix
220   - "find_or_create_by"
221   - end
222   -
223   - def self.suffix
224   - "!"
225   - end
226   -
227   - def instantiator
228   - "create!"
229   - end
230   - end
231 129 end
232 130 end
4 activerecord/test/cases/named_scope_test.rb
@@ -442,11 +442,11 @@ def test_eager_default_scope_relations_are_deprecated
442 442
443 443 class DynamicScopeMatchTest < ActiveRecord::TestCase
444 444 def test_scoped_by_no_match
445   - assert_nil ActiveRecord::DynamicMatchers::ScopedBy.match(nil, "not_scoped_at_all")
  445 + assert_nil ActiveRecord::DynamicMatchers::Method.match(nil, "not_scoped_at_all")
446 446 end
447 447
448 448 def test_scoped_by
449   - match = ActiveRecord::DynamicMatchers::ScopedBy.match(nil, "scoped_by_age_and_sex_and_location")
  449 + match = ActiveRecord::DynamicMatchers::Method.match(nil, "scoped_by_age_and_sex_and_location")
450 450 assert_not_nil match
451 451 assert_equal %w(age sex location), match.attribute_names
452 452 end

0 comments on commit 510cf0a

Please sign in to comment.
Something went wrong with that request. Please try again.