summaryrefslogtreecommitdiff
path: root/lib/declarative_policy/step.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/declarative_policy/step.rb')
-rw-r--r--lib/declarative_policy/step.rb88
1 files changed, 0 insertions, 88 deletions
diff --git a/lib/declarative_policy/step.rb b/lib/declarative_policy/step.rb
deleted file mode 100644
index c289c17cc19..00000000000
--- a/lib/declarative_policy/step.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-module DeclarativePolicy
- # 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.
- class Step
- attr_reader :context, :rule, :action
- def initialize(context, rule, action)
- @context = context
- @rule = rule
- @action = action
- end
-
- # 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)
- def ==(other)
- @context == other.context && @rule == other.rule && @action == other.action
- end
-
- # 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.
- 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
-
- def with_action(action)
- Step.new(@context, @rule, action)
- end
-
- def enable?
- @action == :enable
- end
-
- def prevent?
- @action == :prevent
- end
-
- # This rather complex method allows us to split rules into parts so that
- # they can be sorted independently for better optimization
- 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
-
- def pass?
- @rule.pass?(@context)
- end
-
- def repr
- "#{@action} when #{@rule.repr} (#{@context.repr})"
- end
- end
-end