lib/pundit/matchers/utils/policy_info.rb in pundit-matchers-2.3.0 vs lib/pundit/matchers/utils/policy_info.rb in pundit-matchers-3.0.0.beta1

- old
+ new

@@ -1,30 +1,91 @@ # frozen_string_literal: true module Pundit module Matchers module Utils - # Collects all details about given policy class. + # This class provides methods to retrieve information about a policy class, + # such as the actions it defines and which of those actions are permitted + # or forbidden. It also provides a string representation of the policy class name + # and the user object associated with the policy. class PolicyInfo + # Error message when policy does not respond to `user_alias`. + USER_NOT_IMPLEMENTED_ERROR = <<~MSG + '%<policy>s' does not implement '%<user_alias>s'. You may want to + configure an alias, which you can do as follows: + + Pundit::Matchers.configure do |config| + # Alias for all policies + config.default_user_alias = :%<user_alias>s + + # Per-policy alias + config.user_aliases = { '%<policy>s' => :%<user_alias>s } + end + MSG + attr_reader :policy + # Initializes a new instance of PolicyInfo. + # + # @param policy [Class] The policy class to collect details about. def initialize(policy) @policy = policy + check_user_alias! end + # Returns a string representation of the policy class name. + # + # @return [String] A string representation of the policy class name. + def to_s + policy.class.name + end + + # Returns the user object associated with the policy. + # + # @return [Object] The user object associated with the policy. + def user + @user ||= policy.public_send(user_alias) + end + + # Returns an array of all actions defined in the policy class. + # + # It assumes that actions are defined as public instance methods that end with a question mark. + # + # @return [Array<Symbol>] An array of all actions defined in the policy class. def actions - @actions ||= begin - policy_methods = @policy.public_methods - Object.instance_methods - policy_methods.grep(/\?$/).sort.map { |policy_method| policy_method.to_s.delete_suffix('?').to_sym } + @actions ||= policy_public_methods.grep(/\?$/).sort.map do |policy_method| + policy_method.to_s.delete_suffix('?').to_sym end end + # Returns an array of all permitted actions defined in the policy class. + # + # @return [Array<Symbol>] An array of all permitted actions defined in the policy class. def permitted_actions - @permitted_actions ||= actions.select { |action| policy.public_send("#{action}?") } + @permitted_actions ||= actions.select { |action| policy.public_send(:"#{action}?") } end + # Returns an array of all forbidden actions defined in the policy class. + # + # @return [Array<Symbol>] An array of all forbidden actions defined in the policy class. def forbidden_actions - actions - permitted_actions + @forbidden_actions ||= actions - permitted_actions + end + + private + + def policy_public_methods + @policy_public_methods ||= policy.public_methods - Object.instance_methods + end + + def user_alias + @user_alias ||= Pundit::Matchers.configuration.user_alias(policy) + end + + def check_user_alias! + return if policy.respond_to?(user_alias) + + raise ArgumentError, format(USER_NOT_IMPLEMENTED_ERROR, policy: self, user_alias: user_alias) end end end end end