lib/policy/follower.rb in policy-1.2.0 vs lib/policy/follower.rb in policy-2.0.0
- old
+ new
@@ -1,142 +1,102 @@
# encoding: utf-8
module Policy
- # Adds features for the object to follow external policies
+ # Interface for the class that follows policies
module Follower
- require_relative "follower/names"
- require_relative "follower/followed_policy"
- require_relative "follower/followed_policies"
-
- # Methods to be added to the class the module is included to
- #
- # @private
+ # Methods to be added to the follower class
module ClassMethods
- # @!attribute [r] followed_policies
- # The collection of policies to be followed by instances of the class
+ # Declares a policy to be followed
#
- # @return [Policy::Follower::FollowedPolicies]
+ # Mutates the object by adding an item to its {#policies}.
#
- # @private
- def followed_policies
- @followed_policies ||= FollowedPolicies.new
+ # @param [Symbol] name
+ #
+ # @return [:follows_policy] the name of the method
+ def follows_policy(name)
+ policies.add name
+
+ :follows_policy
end
- # Adds a policy to the list of {#followed_policies}
+ # Declares policies to be followed
#
- # @param [Class] policy
- # the policy object klass
- # @param [Array<#to_sym>] attributes
- # the list of attributes of the instance the policy should be applied to
+ # Mutates the object by adding items to its {#policies}.
#
- # @option [#to_sym] :as
- # the name for the policy to be used for selecting it
- # in {#follow_policies!} and {#follow_policies?} methods
+ # @param [Symbol, Array<Symbol>] names
#
- # @return [undefined]
- def follow_policy(policy, *attributes, as: nil)
- object = FollowedPolicy.new(__policies__, policy, as, *attributes)
- followed_policies.add object
+ # @return [:follows_policies] the name of the method
+ def follows_policies(*names)
+ names.each(&method(:follows_policy))
+
+ :follows_policies
end
- # Changes the namespace for applied policies
+ # @!attribute [r] policies
+ # The collection of followed policies
#
- # @example For Policies::Finances::TransferConsistency
- # use_policies Policies::Finances do
- # apply_policy :TransferConstistency, :debet, :credit
- # end
- #
- # @param [Module] namespace
- #
- # @yield the block in the current scope
- #
- # @return [undefined]
- def use_policies(namespace, &block)
- @__policies__ = namespace
- instance_eval(&block)
- ensure
- @__policies__ = nil
+ # @return [Policy::Follower::Policies]
+ def policies
+ @policies ||= Policies.new(self)
end
- private
-
- def __policies__
- @__policies__ ||= self
- end
-
end
- # Checks whether an instance meets selected policies
+ # Checks whether an object follows all its policies or subset of policies
#
- # Mutates the object by adding new #errors
+ # @overload follow_policies?()
+ # Checks whether an object follows all registered policies
#
- # @param [Array<#to_sym>] names
- # the ordered list of names to select policies by
- # when not names selected all policies will be applied
+ # @overload follow_policies?(names)
+ # Checks whether an object follows given policies
#
- # @raise [Policy::ViolationError]
- # unless all selected policies has been met
+ # @param [#to_sym, Array<#to_sym>] names
#
- # @return [undefined]
- def follow_policies!(*names)
- followed_policies.apply_to self, *names
- rescue ViolationError => error
- collect_errors_from(error)
- raise
- end
-
- # Syntax shugar for the {#follow_policies!} with one argument
+ # @raise [Policy::Follower::NameError]
+ # if the policy is not registered by name
#
- # @param [#to_sym] name
- # the name of the policy to follow
+ # @raise [NoMethodError]
+ # if the name not implemented as follower's instance method
+ # @raise [ViolationError]
+ # if the policy is violated by the follower
#
- # @raise (see #follow_policies!)
- #
- # @return [undefined]
- def follow_policy!(name)
- follow_policies! name
- end
-
- # Safely checks whether an instance meets selected policies
- #
- # Mutates the object by adding new #errors
- #
- # @param (see #follow_policies!)
- #
- # @return [Boolean]
+ # @return [true] if no exception being raised
def follow_policies?(*names)
- follow_policies!(*names)
+ __policies__
+ .subset(names) # raises NameError
+ .map(&method(:__send__)) # raises NoMethodError
+ .each(&method(:__validate_policy__)) # raises ViolationError
true
- rescue ViolationError
- false
end
- # Syntax shugar for the {#follow_policies?} with one argument
+ # Checks whether an object follows given policy
#
- # @param (see #follow_policy!)
+ # @param [#to_sym] name
+ # the name of the policy to follow
#
+ # @raise (see #follow_policies?)
+ #
# @return (see #follow_policies?)
def follow_policy?(name)
follow_policies? name
end
- private
-
- # @!parse extend Policy::Follower::ClassMethods
- # @!parse include ActiveModel::Validations
+ # @private
def self.included(klass)
- klass.extend(ClassMethods).__send__(:include, Validations)
+ klass.instance_eval { extend ClassMethods }
end
- def followed_policies
- @followed_policies ||= self.class.followed_policies
+ private
+
+ def __validate_policy__(policy)
+ fail ViolationError.new(self, policy) unless policy.valid?
end
- def collect_errors_from(exception)
- exception.messages.each { |text| errors.add :base, text }
+ def __policies__
+ self.class.policies
end
end # module Follower
end # module Policy