Class: Eco::API::Session::Batch::BasePolicy

Inherits:
Object
  • Object
show all
Extended by:
Language::Klass::HelpersBuilt, Language::Models::Hierarchy
Includes:
Language::Methods::DslAble, Enumerable
Defined in:
lib/eco/api/session/batch/base_policy.rb

Overview

Helper class to build a hierarchical model of policies

Examples:

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

Direct Known Subclasses

Policies

Instance Attribute Summary collapse

Attributes included from Language::Models::Hierarchy

#model

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Language::Klass::InheritableClassVars

#inheritable_attrs, #inheritable_class_vars, #inherited

Methods included from Language::Klass::Naming

#instance_variable_name, #to_constant

Methods included from Language::Klass::Hierarchy

#descendants, #descendants?

Methods included from Language::Klass::Builder

#new_class

Methods included from Language::Klass::Uid

#uid

Methods included from Language::Klass::Resolver

#class_resolver, #resolve_class

Methods included from Language::Klass::Const

#if_const, #redef_without_warning

Methods included from Language::Models::Hierarchy

model_attrs, parse_model

Methods included from Language::Methods::DslAble

#evaluate, #method_missing, #respond_to_missing?

Constructor Details

#initialize(attr = nil, _parent: self) ⇒ BasePolicy

rubocop:disable Lint/UnderscorePrefixedVariableName



75
76
77
78
79
# File 'lib/eco/api/session/batch/base_policy.rb', line 75

def initialize(attr = nil, _parent: self) # rubocop:disable Lint/UnderscorePrefixedVariableName
  @_parent  = _parent
  @attr     = attr.to_sym
  @policies = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Eco::Language::Methods::DslAble

Instance Attribute Details

#attr(as_namespace: false) ⇒ Symbol (readonly)

the Symbol name of the current policy

Returns:

  • (Symbol)

    the current value of attr



21
22
23
# File 'lib/eco/api/session/batch/base_policy.rb', line 21

def attr
  @attr
end

#count=(value) ⇒ Object (writeonly)

Sets the attribute count

Parameters:

  • value

    the value to set the attribute count to.



73
74
75
# File 'lib/eco/api/session/batch/base_policy.rb', line 73

def count=(value)
  @count = value
end

#max(value = :unused) ⇒ Integer

max allowed number of occurrences of the property

Returns:

  • (Integer)

    the current value of max



21
22
23
# File 'lib/eco/api/session/batch/base_policy.rb', line 21

def max
  @max
end

#min(value = :unused) ⇒ Integer

min required number of occurrences of the property

Returns:

  • (Integer)

    the current value of min



21
22
23
# File 'lib/eco/api/session/batch/base_policy.rb', line 21

def min
  @min
end

Class Method Details

.policy_attrs(*attrs) ⇒ Object

Attributes of this level of the model that should be included

Parameters:

  • attrs (Array<Symbol>, Array<String>)

    each of the subpolicies of the model that should be available



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/eco/api/session/batch/base_policy.rb', line 47

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
        policy.evaluate(policy, &block)
        self
      else
        policy
      end
    end
  end
end

.policy_class(key) ⇒ Eco::API::Session::Batch::BasePolicy

Note:

for this to work, key should be one of the submodels of the current class' model

If the class for key exists, it returns it. Otherwise it generates it.

Returns:



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/eco/api/session/batch/base_policy.rb', line 32

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

Instance Method Details

#[](attr) ⇒ Array<Eco::API::Session::Batch::BasePolicy>

Returns the used subpolicies.

Parameters:

  • attr (Symbol, String)

    name of the policy

Returns:



147
148
149
# File 'lib/eco/api/session/batch/base_policy.rb', line 147

def [](attr)
  @policies[attr.to_sym]
end

#[]=(attr, value) ⇒ Object

Parameters:

Raises:

  • (ArgumentError)


154
155
156
157
158
159
# File 'lib/eco/api/session/batch/base_policy.rb', line 154

def []=(attr, value)
  msg = "Expected object of Eco::API::Session::Batch::BasePolicy. Given #{value.class}"
  raise ArgumentError, msg unless value.is_a?(Eco::API::Session::Batch::BasePolicy)

  @policies[attr.to_sym] = value
end

#active?(attr) ⇒ Boolean

Returns if attr is an active subpolicy.

Parameters:

  • attr (Symbol, String)

    name of the policy

Returns:

  • (Boolean)

    if attr is an active subpolicy



141
142
143
# File 'lib/eco/api/session/batch/base_policy.rb', line 141

def active?(attr)
  @policies.key?(attr.to_sym)
end

#compliant?(model, recurse: true) ⇒ Boolean

Returns true if model is compliant with the current policy.

Parameters:

  • model (Hash)

    plain hash (or hashable object) with the stats to check policy compliance against

  • recurse (Boolean) (defaults to: true)

    to determine if we only check the current policy or also all active subpolicies

Returns:

  • (Boolean)

    true if model is compliant with the current policy



164
165
166
167
168
169
170
171
172
173
174
# File 'lib/eco/api/session/batch/base_policy.rb', line 164

def compliant?(model, recurse: true)
  unless (hash = model_to_hash(model))
    raise ArgumentError, "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

#each(&block) ⇒ Object



128
129
130
131
132
# File 'lib/eco/api/session/batch/base_policy.rb', line 128

def each(&block)
  return to_enum(:each) unless block

  items.each(&block)
end

#empty?Boolean

Returns true if there are no active subpolicies, false otherwise.

Returns:

  • (Boolean)

    true if there are no active subpolicies, false otherwise



119
120
121
# File 'lib/eco/api/session/batch/base_policy.rb', line 119

def empty?
  count.zero?
end

#itemsArray<Eco::API::Session::Batch::BasePolicy>

Returns the active subpolicies.

Returns:



135
136
137
# File 'lib/eco/api/session/batch/base_policy.rb', line 135

def items
  @policies.values
end

#lengthObject

return [Integer] number of declared subpolicies



114
115
116
# File 'lib/eco/api/session/batch/base_policy.rb', line 114

def length
  count
end

#max?(value) ⇒ Boolen

Note:

if there's no max defined, it always returns true

Returns true if value is lesser or equal to min.

Parameters:

  • value (Integer)

    value to check if it's in the maximum allowed

Returns:

  • (Boolen)

    true if value is lesser or equal to min



109
110
111
# File 'lib/eco/api/session/batch/base_policy.rb', line 109

def max?(value)
  !max || !value || (max >= value)
end

#min?(value) ⇒ Boolen

Note:

if there's no min defined, it always returns true

Returns true if value is grater or equal to min.

Parameters:

  • value (Integer)

    value to check if it's in the minimum required

Returns:

  • (Boolen)

    true if value is grater or equal to min



102
103
104
# File 'lib/eco/api/session/batch/base_policy.rb', line 102

def min?(value)
  !min || !value|| (min <= value)
end

#subpolicies?Boolean

Returns true if there are active subpolicies, false otherwise.

Returns:

  • (Boolean)

    true if there are active subpolicies, false otherwise



124
125
126
# File 'lib/eco/api/session/batch/base_policy.rb', line 124

def subpolicies?
  !empty?
end

#uncompliance(model, recurse: true) ⇒ String

Returns message with what failed to meet compliance.

Parameters:

  • model (Hash)

    plain hash (or hashable object) with the stats to check policy compliance against

  • recurse (Boolean) (defaults to: true)

    to determine if we only check the current policy or also all active subpolicies

Returns:

  • (String)

    message with what failed to meet compliance



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/eco/api/session/batch/base_policy.rb', line 196

def uncompliance(model, recurse: true)
  unless (hash = model_to_hash(model))
    raise ArgumentError, "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

#uncompliant(model) ⇒ Array<Eco::API::Session::Batch::BasePolicy>

Returns non-compliant policies for the model.

Parameters:

  • model (Hash)

    plain hash (or hashable object) with the stats to check policy compliance against

Returns:



185
186
187
188
189
190
191
# File 'lib/eco/api/session/batch/base_policy.rb', line 185

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

#validate!(model) ⇒ Object



176
177
178
179
180
181
# File 'lib/eco/api/session/batch/base_policy.rb', line 176

def validate!(model)
  return if compliant?(model)

  msg = uncompliance(model)
  raise "Uncompliance Exception\n#{msg}"
end