Class: CanCan::RulesCompressor

Inherits:
Object
  • Object
show all
Defined in:
lib/cancan/rules_compressor.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rules) ⇒ RulesCompressor

Returns a new instance of RulesCompressor.



8
9
10
11
# File 'lib/cancan/rules_compressor.rb', line 8

def initialize(rules)
  @initial_rules = rules
  @rules_collapsed = compress(@initial_rules)
end

Instance Attribute Details

#initial_rulesObject (readonly)

Returns the value of attribute initial_rules.



6
7
8
# File 'lib/cancan/rules_compressor.rb', line 6

def initial_rules
  @initial_rules
end

#rules_collapsedObject (readonly)

Returns the value of attribute rules_collapsed.



6
7
8
# File 'lib/cancan/rules_compressor.rb', line 6

def rules_collapsed
  @rules_collapsed
end

Instance Method Details

#compress(array) ⇒ Object



13
14
15
16
17
18
19
20
21
22
# File 'lib/cancan/rules_compressor.rb', line 13

def compress(array)
  array = simplify(array)
  idx = array.rindex(&:catch_all?)
  return array unless idx

  value = array[idx]
  array[idx..-1]
    .drop_while { |n| n.base_behavior == value.base_behavior }
    .tap { |a| a.unshift(value) unless value.cannot_catch_all? }
end

#simplify(rules) ⇒ Object

If we have A OR (!A AND anything ), then we can simplify to A OR anything If we have A OR (A OR anything ), then we can simplify to A OR anything If we have !A AND (A OR something), then we can simplify it to !A AND something If we have !A AND (!A AND something), then we can simplify it to !A AND something

So as soon as we see a condition that is the same as the previous one, we can skip it, no matter of the base_behavior



31
32
33
34
35
36
37
38
39
# File 'lib/cancan/rules_compressor.rb', line 31

def simplify(rules)
  seen = Set.new
  rules.reverse_each.filter_map do |rule|
    next if seen.include?(rule.conditions)

    seen.add(rule.conditions)
    rule
  end.reverse
end