Class: DeclarativePolicy::Step

Inherits:
Object
  • Object
show all
Defined in:
lib/declarative_policy/step.rb

Overview

This object represents one step in the runtime decision of whether an ability is allowed. It contains a Rule and a context (instance of DeclarativePolicy::Base), which contains the user, the subject, and the cache. It also contains an “action”, which is the symbol :prevent or :enable.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context, rule, action) ⇒ Step

Returns a new instance of Step.



12
13
14
15
16
# File 'lib/declarative_policy/step.rb', line 12

def initialize(context, rule, action)
  @context = context
  @rule = rule
  @action = action
end

Instance Attribute Details

#actionObject (readonly)

Returns the value of attribute action.



10
11
12
# File 'lib/declarative_policy/step.rb', line 10

def action
  @action
end

#contextObject (readonly)

Returns the value of attribute context.



10
11
12
# File 'lib/declarative_policy/step.rb', line 10

def context
  @context
end

#ruleObject (readonly)

Returns the value of attribute rule.



10
11
12
# File 'lib/declarative_policy/step.rb', line 10

def rule
  @rule
end

Instance Method Details

#==(other) ⇒ Object

In the flattening process, duplicate steps may be generated in the same rule. This allows us to eliminate those (see Runner#steps_by_score and note its use of a Set)



21
22
23
# File 'lib/declarative_policy/step.rb', line 21

def ==(other)
  @context == other.context && @rule == other.rule && @action == other.action
end

#enable?Boolean

Returns:

  • (Boolean)


44
45
46
# File 'lib/declarative_policy/step.rb', line 44

def enable?
  @action == :enable
end

#flattened(roots) ⇒ Object

This rather complex method allows us to split rules into parts so that they can be sorted independently for better optimization



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/declarative_policy/step.rb', line 54

def flattened(roots)
  case @rule
  when Rule::Or
    # A single `Or` step is the same as each of its elements as separate steps
    @rule.rules.flat_map { |r| Step.new(@context, r, @action).flattened(roots) }
  when Rule::Ability
    # This looks like a weird micro-optimization but it buys us quite a lot
    # in some cases. If we depend on an Ability (i.e. a `can?(...)` rule),
    # and that ability *only* has :enable actions (modulo some actions that
    # we already have taken care of), then its rules can be safely inlined.
    steps = @context.runner(@rule.ability).steps.reject { |s| roots.include?(s) }

    if steps.all?(&:enable?)
      # in the case that we are a :prevent step, each inlined step becomes
      # an independent :prevent, even though it was an :enable in its initial
      # context.
      steps.map! { |s| s.with_action(:prevent) } if prevent?

      steps.flat_map { |s| s.flattened(roots) }
    else
      [self]
    end
  else
    [self]
  end
end

#pass?Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/declarative_policy/step.rb', line 81

def pass?
  @rule.pass?(@context)
end

#prevent?Boolean

Returns:

  • (Boolean)


48
49
50
# File 'lib/declarative_policy/step.rb', line 48

def prevent?
  @action == :prevent
end

#reprObject



85
86
87
# File 'lib/declarative_policy/step.rb', line 85

def repr
  "#{@action} when #{@rule.repr} (#{@context.repr})"
end

#scoreObject

In the runner, steps are sorted dynamically by score, so that we are sure to compute them in close to the optimal order.

See also Rule#score, ManifestCondition#score, and Runner#steps_by_score.



29
30
31
32
33
34
35
36
37
38
# File 'lib/declarative_policy/step.rb', line 29

def score
  # we slightly prefer the preventative actions
  # since they are more likely to short-circuit
  case @action
  when :prevent
    @rule.score(@context) * (7.0 / 8)
  when :enable
    @rule.score(@context)
  end
end

#with_action(action) ⇒ Object



40
41
42
# File 'lib/declarative_policy/step.rb', line 40

def with_action(action)
  Step.new(@context, @rule, action)
end