1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Refactor generated_relation_methods to remove duplicated code on ClassSpecificRelation

This commit is contained in:
Ryuta Kamizono 2019-02-28 01:32:57 +09:00
parent 634953af94
commit 06eabecfc0

View file

@ -1,5 +1,7 @@
# frozen_string_literal: true
require "mutex_m"
module ActiveRecord
module Delegation # :nodoc:
module DelegateCache # :nodoc:
@ -31,6 +33,10 @@ module ActiveRecord
super
end
def generate_relation_method(method)
generated_relation_methods.generate_method(method)
end
protected
def include_relation_methods(delegate)
superclass.include_relation_methods(delegate) unless base_class?
@ -39,27 +45,32 @@ module ActiveRecord
private
def generated_relation_methods
@generated_relation_methods ||= Module.new.tap do |mod|
mod_name = "GeneratedRelationMethods"
const_set mod_name, mod
private_constant mod_name
end
@generated_relation_methods ||= GeneratedRelationMethods.new
end
end
class GeneratedRelationMethods < Module # :nodoc:
include Mutex_m
def generate_method(method)
synchronize do
return if method_defined?(method)
def generate_relation_method(method)
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
generated_relation_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
module_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{method}(*args, &block)
scoping { klass.#{method}(*args, &block) }
end
RUBY
else
generated_relation_methods.define_method(method) do |*args, &block|
define_method(method) do |*args, &block|
scoping { klass.public_send(method, *args, &block) }
end
end
end
end
end
private_constant :GeneratedRelationMethods
extend ActiveSupport::Concern
@ -78,39 +89,17 @@ module ActiveRecord
module ClassSpecificRelation # :nodoc:
extend ActiveSupport::Concern
included do
@delegation_mutex = Mutex.new
end
module ClassMethods # :nodoc:
def name
superclass.name
end
def delegate_to_scoped_klass(method)
@delegation_mutex.synchronize do
return if method_defined?(method)
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
module_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{method}(*args, &block)
scoping { @klass.#{method}(*args, &block) }
end
RUBY
else
define_method method do |*args, &block|
scoping { @klass.public_send(method, *args, &block) }
end
end
end
end
end
private
def method_missing(method, *args, &block)
if @klass.respond_to?(method)
self.class.delegate_to_scoped_klass(method)
@klass.generate_relation_method(method)
scoping { @klass.public_send(method, *args, &block) }
else
super