class Eco::API::Session::Batch::BasePolicy
Helper class to build a hierarchical model of policies @example Usage:
class PolicyModel < Eco::API::Session::Batch::BasePolicy MODEL = {attr1: ["prop1a", "prop1b", {"prop1c": ["prop1c1"]}]} self.model = MODEL policy_attrs *model_attrs end policies = PolicyModel.new("batch_policy") policies.attr1c do |attr1c| attr1c.prop1c1.max = 30 end
@attr_reader attr [Symbol] the Symbol `name` of the current policy @attr_reader max [Integer] `max` allowed number of occurrences of the property @attr_reader min [Integer] `min` required number of occurrences of the property
Attributes
Public Class Methods
# File lib/eco/api/session/batch/base_policy.rb, line 72 def initialize(attr = nil, _parent: self) @_parent = _parent @attr = attr.to_sym @policies = {} end
Attributes of this level of the model that should be included @param attrs [Array<Symbol>, Array<String>] each of the subpolicies of the model that should be available
# File lib/eco/api/session/batch/base_policy.rb, line 41 def policy_attrs(*attrs) attrs = attrs.map(&:to_sym) attrs.each do |attr| method = attr.to_s.freeze var = "@#{method}".freeze define_method(method) do |&block| unless policy = self[attr] klass = self.class.policy_class(attr) policy = self[attr] = klass.new(attr, _parent: self) end if block block.call(policy) self else policy end end end end
If the class for `key` exists, it returns it. Otherwise it generates it. @note for this to work, `key` should be one of the submodels of the current class' `model` @return [Eco::API::Session::Batch::BasePolicy] or subclass thereof
# File lib/eco/api/session/batch/base_policy.rb, line 29 def policy_class(key) key = key.to_sym.freeze class_name = to_constant(key) new_class(class_name, inherits: Eco::API::Session::Batch::BasePolicy) do |klass| klass.model = model[key] klass.policy_attrs *klass.model_attrs end end
Public Instance Methods
@param attr [Symbol, String] name of the policy @return [Array<Eco::API::Session::Batch::BasePolicy>] the used subpolicies
# File lib/eco/api/session/batch/base_policy.rb, line 130 def [](attr) @policies[attr.to_sym] end
@param attr [Symbol, String] name of the policy @param value [Expected object of Eco::API::Session::Batch::BasePolicy] a subpolicy to assign to a name `attr`
# File lib/eco/api/session/batch/base_policy.rb, line 136 def []=(attr, value) raise "Expected object of Eco::API::Session::Batch::BasePolicy. Given #{value.class}" unless value.is_a?(Eco::API::Session::Batch::BasePolicy) @policies[attr.to_sym] = value end
@param attr [Symbol, String] name of the policy @return [Boolean] if `attr` is an active subpolicy
# File lib/eco/api/session/batch/base_policy.rb, line 124 def active?(attr) @policies.key?(attr.to_sym) end
@param model [Hash] plain hash (or hashable object) with the stats to check policy compliance against @param recurse [Boolean] to determine if we only check the current policy or also all active subpolicies @return [Boolean] `true` if `model` is compliant with the current policy
# File lib/eco/api/session/batch/base_policy.rb, line 144 def compliant?(model, recurse: true) unless hash = model_to_hash(model) raise "Expected 'model' to be a Hash (or hashable) object. Given: #{model}" end value = model_attr(hash) good = !model_attr?(hash) || (min?(value) && max?(value)) #pp "batch_policy: '#{attr}' - #{value}: 'min' #{min?(value)}; 'max' #{max?(value)}" good &&= all? {|active| active.compliant?(model, recurse: recurse)} if recurse good end
# File lib/eco/api/session/batch/base_policy.rb, line 112 def each(&block) return to_enum(:each) unless block items.each(&block) end
@return [Boolean] `true` if there are no active subpolicies, `false` otherwise
# File lib/eco/api/session/batch/base_policy.rb, line 103 def empty? count == 0 end
@return [Array<Eco::API::Session::Batch::BasePolicy>] the active subpolicies
# File lib/eco/api/session/batch/base_policy.rb, line 118 def items @policies.values end
return [Integer] number of declared subpolicies
# File lib/eco/api/session/batch/base_policy.rb, line 98 def length count end
@note if there's no `max` defined, it always returns `true` @param value [Integer] value to check if it's in the maximum allowed @return [Boolen] `true` if `value` is lesser or equal to `min`
# File lib/eco/api/session/batch/base_policy.rb, line 93 def max?(value) !max || !value || (max >= value) end
@note if there's no `min` defined, it always returns `true` @param value [Integer] value to check if it's in the minimum required @return [Boolen] `true` if `value` is grater or equal to `min`
# File lib/eco/api/session/batch/base_policy.rb, line 86 def min?(value) !min || !value|| (min <= value) end
@return [Boolean] `true` if there are active subpolicies, `false` otherwise
# File lib/eco/api/session/batch/base_policy.rb, line 108 def subpolicies? !empty? end
@param model [Hash] plain hash (or hashable object) with the stats to check policy compliance against @param recurse [Boolean] to determine if we only check the current policy or also all active subpolicies @return [String] message with what failed to meet compliance
# File lib/eco/api/session/batch/base_policy.rb, line 175 def uncompliance(model, recurse: true) unless hash = model_to_hash(model) raise "Expected 'model' to be a Hash (or hashable) object. Given: #{model}" end msg = "" unless compliant?(hash, recurse: false) value = model_attr(hash) msg += "'#{attr(as_namespace: true)}' fails to meet: " msg += " [ min(#{min}) >= #{value}] " unless min?(value) msg += " [ max(#{max}) <= #{value}] " unless max?(value) msg += "\n" end if recurse map do |active| active.uncompliance(hash, recurse: true) end.compact.tap do |msgs| msg += "\n" + msgs.join("\n") unless msgs.empty? end end msg end
@param model [Hash] plain hash (or hashable object) with the stats to check policy compliance against @return [Array<Eco::API::Session::Batch::BasePolicy>] non-compliant policies for the `model`
# File lib/eco/api/session/batch/base_policy.rb, line 164 def uncompliant(model) each_with_object([]) do |active, arr| arr.concat(active.uncompliant(model)) end.tap do |arr| arr.unshift(self) unless compliant?(model, recurse: false) end end
# File lib/eco/api/session/batch/base_policy.rb, line 155 def validate!(model) unless compliant?(model) msg = self.uncompliance(model) raise "Uncompliance Exception\n#{msg}" end end
Protected Instance Methods
# File lib/eco/api/session/batch/base_policy.rb, line 214 def model_attr(hash) return hash[self.attr] if hash.key?(self.attr) hash[self.attr.to_s] if model_attr?(hash) end
# File lib/eco/api/session/batch/base_policy.rb, line 210 def model_attr?(hash) hash.key?(self.attr) || hash.key?(self.attr.to_s) end
Internal helper to know if we are at the top/root of the hierarchical model @return [Boolean] `true` if this object is the top `root`, `false` otherwise
# File lib/eco/api/session/batch/base_policy.rb, line 202 def root? @_parent == self end
# File lib/eco/api/session/batch/base_policy.rb, line 206 def to_h @policies end
Private Instance Methods
# File lib/eco/api/session/batch/base_policy.rb, line 221 def model_to_hash(model) return model if model.is_a?(Hash) model.to_h if model.respond_to?(:to_h) end