Permalink
Browse files

preloading refactor

  • Loading branch information...
1 parent ecf7143 commit 81f56a3c8ce3ff8e1efeb2776169d3f6a983767a @matthewvermaak committed May 14, 2010
@@ -6,10 +6,21 @@ module Preload
PRELOAD_PERMISSIONABLE_ROLES = :preload_permissionable_roles
PRELOAD_OPTIONS = [PRELOAD_ROLES, PRELOAD_PRINCIPAL_ROLES, PRELOAD_PERMISSIONABLE_ROLES]
- def find(*args)
+ def self.extended(base)
+ unless base.respond_to? :find_without_preloaded_roles
+ base.class_eval %Q{
+ class << self
+ alias_method_chain :find, :preloaded_roles
+ end
+ }
+ end
+ base.send :include, Scope
+ end
+
+ def find_with_preloaded_roles(*args)
if args.last.respond_to? :keys and !(args.last.keys & PRELOAD_OPTIONS).blank?
preload = process_preload_options(args.last)
- results = super
+ results = find_without_preloaded_roles(*args)
if preload[:roles] == true
preload_roles_for(results)
@@ -25,7 +36,7 @@ def find(*args)
results
else
- super
+ find_without_preloaded_roles(*args)
end
end
@@ -87,6 +98,43 @@ def preload_permissionable_roles_for(results)
end
results
end
+
+ module Scope
+ def preload_scope
+ @preload_scope ||= Hash.new([])
+ end
+
+ def preload_scope=(pscope)
+ @preload_scope = pscope
+ end
+
+ def reset_preload_scope
+ @preload_scope = Hash.new([])
+ end
+
+ protected
+ def preload_scope_merge(pscope = Hash.new([]))
+ [:preload_has, :preload_with, :preload_for, :preload_over].each do |m|
+ self.preload_scope[m] = pscope[m] unless pscope[m].blank?
+ end
+ end
+
+ def execute_preload_scope
+ result_set = self.preload_scope.inject(nil) do |result_set, (preload_method, preload_arguments)|
+ if result_set.nil?
+ result_set = self.send(preload_method, *preload_arguments)
+ else
+ result_set = result_set & self.send(preload_method, *preload_arguments)
+ end
+ end
+
+ if result_set.blank?
+ Sanction::Result::BlankArray.new(self)
+ else
+ Sanction::Result::SingleArray.new(self)
+ end
+ end
+ end
end
end
end
@@ -39,24 +39,11 @@ def for?(*args)
module InstanceMethods
def for(*args)
- if self.permissionable_roles_loaded?
- found_for = false
-
- if args.include? Sanction::Role::Definition::ANY_TOKEN
- found_for = true if self.permissionable_roles.detect {|r| r.principal_type != nil}
- else
- args.each do |a|
- raise Sanction::Role::Error::UnknownPrincipal.new("Unknown principal: #{a}") unless Sanction::Role::Definition.valid_principal? a
+ args ||= Sanction::Role::Definition::ANY_TOKEN
- found_for = true if self.permissionable_roles.detect {|r| r.principal_match? a}
- end
- end
-
- if found_for
- Sanction::Result::SingleArray.construct(self)
- else
- Sanction::Result::BlankArray.construct(self)
- end
+ if self.permissionable_roles_loaded?
+ self.preload_scope_merge({:preload_for => args})
+ self.execute_preload_scope
else
self.class.as_permissionable(self).for_scope_method(*args)
end
@@ -65,6 +52,21 @@ def for(*args)
def for?(*args)
!self.for(*args).blank?
end
+
+ private
+ def preload_for(*args)
+ if args.include? Sanction::Role::Definition::ANY_TOKEN
+ self.permissionable_roles.select {|r| r.principal_type != nil}
+ else
+ p_roles = []
+ args.each do |a|
+ raise Sanction::Role::Error::UnknownPrincipal.new("Unknown principal: #{a}") unless Sanction::Role::Definition.valid_principal? a
+
+ p_roles << self.permissionable_roles.select {|r| r.principal_match? a}
+ end
+ p_roles.flatten.uniq
+ end
+ end
end
end
end
@@ -30,20 +30,11 @@ def with?(*role_names)
module InstanceMethods
def with(*role_names)
- if self.permissionable_roles_loaded?
- blank_result = true
- if role_names.include? Sanction::Role::Definition::ANY_TOKEN
- blank_result = false unless self.permissionable_roles.blank?
- else
- p_roles = Sanction::Role::Definition.process_role_or_permission_names_for_permissionable(self.class, *role_names).map(&:to_sym)
- blank_result = false unless self.permissionable_roles.detect { |r| p_roles.include? r.name.to_sym }.blank?
- end
+ role_names ||= Sanction::Role::Definition::ANY_TOKEN
- if blank_result
- Sanction::Result::BlankArray.construct(self)
- else
- Sanction::Result::SingleArray.construct(self)
- end
+ if self.permissionable_roles_loaded?
+ self.preload_scope_merge({:preload_with => role_names})
+ self.execute_preload_scope
else
self.class.as_permissionable(self).with_scope_method(*role_names)
end
@@ -52,6 +43,16 @@ def with(*role_names)
def with?(*role_names)
!with(*role_names).blank?
end
+
+ private
+ def preload_with(*role_names)
+ if role_names.include? Sanction::Role::Definition::ANY_TOKEN
+ self.permissionable_roles
+ else
+ p_roles = Sanction::Role::Definition.process_role_or_permission_names_for_permissionable(self.class, *role_names).map(&:to_sym)
+ self.permissionable_roles.select { |r| p_roles.include? r.name.to_sym }
+ end
+ end
end
end
end
@@ -31,20 +31,11 @@ def has?(*role_names)
module InstanceMethods
def has(*role_names)
- if self.principal_roles_loaded?
- blank_result = true
- if role_names.include? Sanction::Role::Definition::ANY_TOKEN
- blank_result = false unless self.principal_roles.blank?
- else
- p_roles = Sanction::Role::Definition.process_role_or_permission_names_for_principal(self.class, *role_names).map(&:to_sym)
- blank_result = false unless self.principal_roles.detect { |r| p_roles.include? r.name.to_sym }.blank?
- end
+ role_names ||= Sanction::Role::Definition::ANY_TOKEN
- if blank_result
- Sanction::Result::BlankArray.construct(self)
- else
- Sanction::Result::SingleArray.construct(self)
- end
+ if self.principal_roles_loaded?
+ self.preload_scope_merge({:preload_has => role_names})
+ self.execute_preload_scope
else
self.class.as_principal(self).has_scope_method(*role_names)
end
@@ -53,6 +44,16 @@ def has(*role_names)
def has?(*role_names)
!has(*role_names).blank?
end
+
+ private
+ def preload_has(*role_names)
+ if role_names.include? Sanction::Role::Definition::ANY_TOKEN
+ self.principal_roles
+ else
+ p_roles = Sanction::Role::Definition.process_role_or_permission_names_for_principal(self.class, *role_names).map(&:to_sym)
+ self.principal_roles.select { |r| p_roles.include? r.name.to_sym }
+ end
+ end
end
end
end
@@ -8,24 +8,11 @@ def self.included(base)
module InstanceMethods
def over(*args)
- if self.principal_roles_loaded?
- found_over = false
-
- if args.include? Sanction::Role::Definition::ANY_TOKEN
- found_over = true if self.principal_roles.detect {|r| r.permissionable_type != nil}
- else
- args.each do |a|
- raise Sanction::Role::Error::UnknownPermissionable.new("Unknown permissionable: #{a}") unless Sanction::Role::Definition.valid_permissionable? a
+ args ||= Sanction::Role::Definition::ANY_TOKEN
- found_over = true if self.principal_roles.detect {|r| r.permissionable_match? a}
- end
- end
-
- if found_over
- Sanction::Result::SingleArray.construct(self)
- else
- Sanction::Result::BlankArray.construct(self)
- end
+ if self.principal_roles_loaded?
+ self.preload_scope_merge({:preload_over => args})
+ self.execute_preload_scope
else
self.class.as_principal(self).over_scope_method(*args)
end
@@ -34,6 +21,21 @@ def over(*args)
def over?(*args)
!over(*args).blank?
end
+
+ private
+ def preload_over(*args)
+ if args.include? Sanction::Role::Definition::ANY_TOKEN
+ self.principal_roles.self {|r| r.permissionable_type != nil}
+ else
+ p_roles = []
+ args.each do |a|
+ raise Sanction::Role::Error::UnknownPermissionable.new("Unknown permissionable: #{a}") unless Sanction::Role::Definition.valid_permissionable? a
+
+ p_roles << self.principal_roles.select {|r| r.permissionable_match? a}
+ end
+ p_roles.flatten.uniq
+ end
+ end
end
module ClassMethods
@@ -1,32 +1,32 @@
module Sanction
module Result
- class BlankArray
- def self.construct(decoy)
+ class BlankArray < BlankSlate
+ def initialize(decoy)
@decoy = decoy
-
- a = []
- a.instance_variable_set(:@decoy, @decoy)
- (class << a; self; end).send(:include, MethodMissing)
- a
end
- module MethodMissing
- def method_missing(m, *args)
- if @decoy.class.respond_to? :is_a_principal? and @decoy.class.is_a_principal?
- if [:has, :over].include? m
- Sanction::Result::BlankArray.construct(@decoy)
- elsif [:has?, :over?].include? m
- false
- end
- elsif @decoy.class.respond_to? :is_a_permissionable? and @decoy.class.is_a_permissionable?
- if [:with, :for].include? m
- Sanction::Result::BlankArray.construct(@decoy)
- elsif [:with?, :for?].include? m
- false
- end
+ def method_missing(m, *args)
+ if @decoy.class.respond_to? :is_a_principal? and @decoy.class.is_a_principal?
+ if [:has, :over].include? m
+ Sanction::Result::BlankArray.new(@decoy)
+ elsif [:has?, :over?].include? m
+ false
else
- @decoy.send(m, *args)
+ @decoy.reset_preload_scope
+ [].send(m, *args)
end
+ elsif @decoy.class.respond_to? :is_a_permissionable? and @decoy.class.is_a_permissionable?
+ if [:with, :for].include? m
+ Sanction::Result::BlankArray.new(@decoy)
+ elsif [:with?, :for?].include? m
+ false
+ else
+ @decoy.reset_preload_scope
+ [].send(m, *args)
+ end
+ else
+ @decoy.reset_preload_scope
+ [].send(m, *args)
end
end
end
@@ -1,16 +1,16 @@
module Sanction
module Result
- class SingleArray
- def self.construct(decoy)
- a = [decoy]
- a.instance_variable_set(:@decoy, decoy)
- (class << a; self; end).send(:include, MethodMissing)
- a
+ class SingleArray < BlankSlate
+ def initialize(decoy)
+ @decoy = decoy
end
- module MethodMissing
- def method_missing(m, *args)
+ def method_missing(m, *args)
+ if [:has, :for, :over, :with, :has?, :for?, :over?, :with?].include? m
@decoy.send(m, *args)
+ else
+ @decoy.reset_preload_scope
+ [@decoy].send(m, *args)
end
end
end
@@ -584,4 +584,19 @@ def test_iteration_of_preloaded_roles
assert !Person.first.has?(:reader)
end
+
+ def test_preload_roles_with_multiples
+ Person.first.grant(:writer, Magazine.first)
+ Person.first.grant(:editor, Magazine.last)
+
+ person = Person.first :preload_roles => true
+
+ Person.first.revoke(:writer, Magazine.first)
+ Person.first.revoke(:editor, Magazine.last)
+
+ assert person.has(:writer).over?(Magazine.first)
+ assert person.has(:editor).over?(Magazine.last)
+ assert !person.has(:editor).over?(Magazine.first)
+ assert !person.has(:writer).over?(Magazine.last)
+ end
end

0 comments on commit 81f56a3

Please sign in to comment.