@@ -7,114 +7,99 @@ def respond_to_missing?(name, _)
7
7
if self == Base
8
8
super
9
9
else
10
- match = Method . match ( self , name )
11
- match && match . valid? || super
10
+ super || begin
11
+ match = Method . match ( name )
12
+ match && match . valid? ( self , name )
13
+ end
12
14
end
13
15
end
14
16
15
17
def method_missing ( name , ...)
16
- match = Method . match ( self , name )
18
+ match = Method . match ( name )
17
19
18
- if match && match . valid?
19
- match . define
20
+ if match && match . valid? ( self , name )
21
+ match . define ( self , name )
20
22
send ( name , ...)
21
23
else
22
24
super
23
25
end
24
26
end
25
27
26
28
class Method
27
- @matchers = [ ]
28
-
29
29
class << self
30
- attr_reader :matchers
31
-
32
- def match ( model , name )
33
- klass = matchers . find { |k | k . pattern . match? ( name ) }
34
- klass . new ( model , name ) if klass
30
+ def match ( name )
31
+ FindBy . match? ( name ) || FindByBang . match? ( name )
35
32
end
36
33
37
- def pattern
38
- @pattern ||= / \A #{ prefix } _([_a-zA-Z] \w *) #{ suffix } \Z /
34
+ def valid? ( model , name )
35
+ attribute_names ( model , name . to_s ) . all? { | name | model . columns_hash [ name ] || model . reflect_on_aggregation ( name . to_sym ) }
39
36
end
40
37
41
- def prefix
42
- raise NotImplementedError
38
+ def define ( model , name )
39
+ model . class_eval <<-CODE , __FILE__ , __LINE__ + 1
40
+ def self.#{ name } (#{ signature ( model , name ) } )
41
+ #{ body ( model , name ) }
42
+ end
43
+ CODE
43
44
end
44
45
45
- def suffix
46
- ""
47
- end
48
- end
46
+ private
47
+ def make_pattern ( prefix , suffix )
48
+ / \A #{ prefix } _([_a-zA-Z] \w *) #{ suffix } \Z /
49
+ end
49
50
50
- attr_reader :model , :name , :attribute_names
51
+ def attribute_names ( model , name )
52
+ attribute_names = name . match ( pattern ) [ 1 ] . split ( "_and_" )
53
+ attribute_names . map! { |name | model . attribute_aliases [ name ] || name }
54
+ end
51
55
52
- def initialize ( model , method_name )
53
- @model = model
54
- @name = method_name . to_s
55
- @attribute_names = @name . match ( self . class . pattern ) [ 1 ] . split ( "_and_" )
56
- @attribute_names . map! { |name | @model . attribute_aliases [ name ] || name }
57
- end
56
+ def body ( model , method_name )
57
+ "#{ finder } (#{ attributes_hash ( model , method_name ) } )"
58
+ end
58
59
59
- def valid?
60
- attribute_names . all? { |name | model . columns_hash [ name ] || model . reflect_on_aggregation ( name . to_sym ) }
61
- end
60
+ # The parameters in the signature may have reserved Ruby words, in order
61
+ # to prevent errors, we start each param name with `_`.
62
+ def signature ( model , method_name )
63
+ attribute_names ( model , method_name . to_s ) . map { |name | "_#{ name } " } . join ( ", " )
64
+ end
62
65
63
- def define
64
- model . class_eval <<-CODE , __FILE__ , __LINE__ + 1
65
- def self. #{ name } ( #{ signature } )
66
- #{ body }
66
+ # Given that the parameters starts with `_`, the finder needs to use the
67
+ # same parameter name.
68
+ def attributes_hash ( model , method_name )
69
+ "{" + attribute_names ( model , method_name ) . map { | name | ": #{ name } => _ #{ name } " } . join ( "," ) + "}"
67
70
end
68
- CODE
69
71
end
72
+ end
70
73
71
- private
72
- def body
73
- "#{ finder } (#{ attributes_hash } )"
74
- end
74
+ class FindBy < Method
75
+ @pattern = make_pattern ( "find_by" , "" )
75
76
76
- # The parameters in the signature may have reserved Ruby words, in order
77
- # to prevent errors, we start each param name with `_`.
78
- def signature
79
- attribute_names . map { |name | "_#{ name } " } . join ( ", " )
80
- end
77
+ class << self
78
+ attr_reader :pattern
81
79
82
- # Given that the parameters starts with `_`, the finder needs to use the
83
- # same parameter name.
84
- def attributes_hash
85
- "{" + attribute_names . map { |name | ":#{ name } => _#{ name } " } . join ( "," ) + "}"
80
+ def match? ( name )
81
+ pattern . match? ( name ) && self
86
82
end
87
83
88
84
def finder
89
- raise NotImplementedError
85
+ "find_by"
90
86
end
91
- end
92
-
93
- class FindBy < Method
94
- Method . matchers << self
95
-
96
- def self . prefix
97
- "find_by"
98
- end
99
-
100
- def finder
101
- "find_by"
102
87
end
103
88
end
104
89
105
90
class FindByBang < Method
106
- Method . matchers << self
91
+ @pattern = make_pattern ( "find_by" , "!" )
107
92
108
- def self . prefix
109
- "find_by"
110
- end
93
+ class << self
94
+ attr_reader :pattern
111
95
112
- def self . suffix
113
- "!"
114
- end
96
+ def match? ( name )
97
+ pattern . match? ( name ) && self
98
+ end
115
99
116
- def finder
117
- "find_by!"
100
+ def finder
101
+ "find_by!"
102
+ end
118
103
end
119
104
end
120
105
end
0 commit comments