Use methods to get ScopeRegistry values rather than symbols

We're spending time validating symbol parameters of the ScopeRegistry.
It's an internal class, and we can stop validating symbols by converting
to methods (you'll automatically get an error if you try to call a
method that doesn't exist).  Second, since we only have 3 things to keep
track of, rather than keep those things in a hash, just break it out in
to 3 instance variables.  (This is absolutely not a memory bottleneck,
but technically this patch will save some memory as the 3 ivars will be
embedded in the object rather than require a full st_table for the
original wrapper hash)
This commit is contained in:
Aaron Patterson 2021-04-02 12:14:57 -07:00
parent bcf3752247
commit 73c18888ad
No known key found for this signature in database
GPG Key ID: 953170BCB4FFAFC6
3 changed files with 37 additions and 27 deletions

@ -24,19 +24,23 @@ def scope_attributes?
end
def current_scope(skip_inherited_scope = false)
ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
ScopeRegistry.current_scope(self, skip_inherited_scope)
end
def current_scope=(scope)
ScopeRegistry.set_value_for(:current_scope, self, scope)
ScopeRegistry.set_current_scope(self, scope)
end
def global_current_scope(skip_inherited_scope = false)
ScopeRegistry.value_for(:global_current_scope, self, skip_inherited_scope)
ScopeRegistry.global_current_scope(self, skip_inherited_scope)
end
def global_current_scope=(scope)
ScopeRegistry.set_value_for(:global_current_scope, self, scope)
ScopeRegistry.set_global_current_scope(self, scope)
end
def scope_registry
ScopeRegistry.instance
end
end
@ -80,34 +84,40 @@ class ScopeRegistry # :nodoc:
VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope, :global_current_scope]
def initialize
@registry = Hash.new { |hash, key| hash[key] = {} }
@current_scope = {}
@ignore_default_scope = {}
@global_current_scope = {}
end
# Obtains the value for a given +scope_type+ and +model+.
def value_for(scope_type, model, skip_inherited_scope = false)
raise_invalid_scope_type!(scope_type)
return @registry[scope_type][model.name] if skip_inherited_scope
klass = model
base = model.base_class
while klass <= base
value = @registry[scope_type][klass.name]
return value if value
klass = klass.superclass
VALID_SCOPE_TYPES.each do |type|
class_eval <<-eorb, __FILE__, __LINE__
def #{type}(model, skip_inherited_scope = false)
value_for(@#{type}, model, skip_inherited_scope)
end
end
# Sets the +value+ for a given +scope_type+ and +model+.
def set_value_for(scope_type, model, value)
raise_invalid_scope_type!(scope_type)
@registry[scope_type][model.name] = value
def set_#{type}(model, value)
set_value_for(@#{type}, model, value)
end
eorb
end
private
def raise_invalid_scope_type!(scope_type)
if !VALID_SCOPE_TYPES.include?(scope_type)
raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
# Obtains the value for a given +scope_type+ and +model+.
def value_for(scope_type, model, skip_inherited_scope = false)
return scope_type[model.name] if skip_inherited_scope
klass = model
base = model.base_class
while klass <= base
value = scope_type[klass.name]
return value if value
klass = klass.superclass
end
end
# Sets the +value+ for a given +scope_type+ and +model+.
def set_value_for(scope_type, model, value)
scope_type[model.name] = value
end
end
end
end

@ -173,11 +173,11 @@ def execute_scope?(all_queries, default_scope_obj)
end
def ignore_default_scope?
ScopeRegistry.value_for(:ignore_default_scope, base_class)
ScopeRegistry.ignore_default_scope(base_class)
end
def ignore_default_scope=(ignore)
ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
ScopeRegistry.set_ignore_default_scope(base_class, ignore)
end
# The ignore_default_scope flag is used to prevent an infinite recursion

@ -1259,9 +1259,9 @@ def test_current_scope_is_reset
UnloadablePost.unloadable
klass = UnloadablePost
assert_not_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, klass)
assert_not_nil ActiveRecord::Scoping::ScopeRegistry.current_scope(klass)
ActiveSupport::Dependencies.remove_unloadable_constants!
assert_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, klass)
assert_nil ActiveRecord::Scoping::ScopeRegistry.current_scope(klass)
ensure
Object.class_eval { remove_const :UnloadablePost } if defined?(UnloadablePost)
end