Class: Browsable::PolicyResolver
- Inherits:
-
Object
- Object
- Browsable::PolicyResolver
- Defined in:
- lib/browsable/policy_resolver.rb
Overview
Maps a ‘(controller_class, action_name)` pair to the effective Browsable Policy. This is what runtime mode uses, per response, to decide which browsers an endpoint’s assets must support.
Resolution rules (matching Rails’ own filter-callback semantics):
1. Walk the controller's ancestor chain from the most-specific class up
to ApplicationController, ignoring anonymous classes and modules.
2. For each class, look up its allow_browser callsites (PolicyScanner
data) and pick the *last* call whose `only:`/`except:` filter matches.
3. The first ancestor with a matching call wins — its last matching call
becomes the effective policy.
4. If no call matches, return the configured default Policy (the policy
from ApplicationController, falling through to the project default).
The scanned policy data is built lazily on first use. Tests can call ‘.reset!` between examples to swap roots without process restart.
Instance Attribute Summary collapse
-
#action_name ⇒ Object
readonly
Returns the value of attribute action_name.
-
#controller_class ⇒ Object
readonly
Returns the value of attribute controller_class.
Class Method Summary collapse
-
.configure(root: nil, policies: nil, default: nil) ⇒ Object
Inject pre-scanned data — used by drivers (which know the Rails root) and by tests (which want to bypass disk).
- .default_policy ⇒ Object
-
.for(controller_class, action_name) ⇒ Object
Convenience: resolve a single controller#action using the shared state.
-
.lookup ⇒ Object
{ “PostsController” => [PolicyScanner::Policy, …] }, built once.
- .policies ⇒ Object
-
.reset! ⇒ Object
Forget any cached state.
- .root ⇒ Object
Instance Method Summary collapse
-
#initialize(controller_class, action_name) ⇒ PolicyResolver
constructor
A new instance of PolicyResolver.
- #resolve ⇒ Object
Constructor Details
#initialize(controller_class, action_name) ⇒ PolicyResolver
Returns a new instance of PolicyResolver.
79 80 81 82 |
# File 'lib/browsable/policy_resolver.rb', line 79 def initialize(controller_class, action_name) @controller_class = controller_class @action_name = action_name&.to_s end |
Instance Attribute Details
#action_name ⇒ Object (readonly)
Returns the value of attribute action_name.
77 78 79 |
# File 'lib/browsable/policy_resolver.rb', line 77 def action_name @action_name end |
#controller_class ⇒ Object (readonly)
Returns the value of attribute controller_class.
77 78 79 |
# File 'lib/browsable/policy_resolver.rb', line 77 def controller_class @controller_class end |
Class Method Details
.configure(root: nil, policies: nil, default: nil) ⇒ Object
Inject pre-scanned data — used by drivers (which know the Rails root) and by tests (which want to bypass disk).
30 31 32 33 34 35 |
# File 'lib/browsable/policy_resolver.rb', line 30 def configure(root: nil, policies: nil, default: nil) @root = root @policies = policies @default = default @lookup = nil end |
.default_policy ⇒ Object
53 54 55 |
# File 'lib/browsable/policy_resolver.rb', line 53 def default_policy @default ||= build_default_policy end |
.for(controller_class, action_name) ⇒ Object
Convenience: resolve a single controller#action using the shared state.
24 25 26 |
# File 'lib/browsable/policy_resolver.rb', line 24 def for(controller_class, action_name) new(controller_class, action_name).resolve end |
.lookup ⇒ Object
{ “PostsController” => [PolicyScanner::Policy, …] }, built once.
58 59 60 |
# File 'lib/browsable/policy_resolver.rb', line 58 def lookup @lookup ||= policies.group_by(&:scope) end |
.policies ⇒ Object
49 50 51 |
# File 'lib/browsable/policy_resolver.rb', line 49 def policies @policies ||= PolicyScanner.call(root) end |
.reset! ⇒ Object
Forget any cached state. Called between test files.
38 39 40 41 42 43 |
# File 'lib/browsable/policy_resolver.rb', line 38 def reset! @root = nil @policies = nil @default = nil @lookup = nil end |
.root ⇒ Object
45 46 47 |
# File 'lib/browsable/policy_resolver.rb', line 45 def root @root ||= (defined?(Rails) && Rails.application ? Rails.root.to_s : Dir.pwd) end |
Instance Method Details
#resolve ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/browsable/policy_resolver.rb', line 84 def resolve return self.class.default_policy if controller_class.nil? || action_name.nil? || action_name.empty? ancestor_class_names.each do |name| calls = self.class.lookup[name] next unless calls && !calls.empty? match = calls.reverse.find { |call| applies?(call) } next unless match return policy_from(match, scope: name, source: same_class?(name) ? :controller : :ancestor) end self.class.default_policy end |