Class: Rulix::Base

Inherits:
Object
  • Object
show all
Includes:
Registry
Defined in:
lib/rulix/base.rb

Direct Known Subclasses

Mutator, Validator

Class Method Summary collapse

Methods included from Registry

included

Class Method Details

.data_for_ruleset(dataset, ruleset) ⇒ Object



41
42
43
44
45
# File 'lib/rulix/base.rb', line 41

def self.data_for_ruleset dataset, ruleset
  seed = {}

  reduce_into_hash seed, dataset, ruleset
end

.handle_merge(data_obj, operation_obj) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/rulix/base.rb', line 33

def self.handle_merge data_obj, operation_obj
  operation_obj = [operation_obj] unless operation_obj.is_a? Array

  ops = get_operations operation_obj

  [data_obj, ops]
end

.reduce_into_hash(hash, dataset, ruleset) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/rulix/base.rb', line 47

def self.reduce_into_hash hash, dataset, ruleset
  ruleset.reduce(hash) do |data_hash, values|
    key, rule_val = values

    nested_value = value_from_dataset dataset, key

    if rule_val.is_a?(Hash) && (nested_value.is_a?(Hash) || rule_val.keys.all? { |k| nested_value.respond_to?(k) })
      seed = {}

      data_hash[key] = reduce_into_hash seed, nested_value, rule_val
    elsif nested_value.is_a?(Array) && nested_value.all? { |val| val.is_a?(Hash) }
      seed = {}

      data_hash[key] = nested_value.map do |nested_val|
        reduce_into_hash seed, nested_val, rule_val.first
      end
    else
      data_hash[key] = nested_value
    end

    data_hash
  end
end

.run(dataset, ruleset) ⇒ Object

This will ALWAYS return a hash with symbolized keys This was a design decision to reduce the potential for dependencies by introducing HashWithIndifferentAccess or edge cases in rule registration and such



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/rulix/base.rb', line 9

def self.run dataset, ruleset
  return to_enum(__callee__) unless block_given?

  dataset = dataset.deep_symbolize_keys if dataset.is_a?(Hash)

  dataset = data_for_ruleset dataset, ruleset

  dataset.deep_merge ruleset do |key, data_obj, operation_obj|
    if (data_obj.is_a?(Array) && data_obj.all? { |o| o.respond_to?(:deep_merge) })
      data_obj.map do |data|
        data.deep_merge operation_obj.first do |k, d, o|
          yield *handle_merge(d, o)
        end
      end
    elsif data_obj.is_a?(Array)
      data_obj.map do |obj|
        yield *handle_merge(obj, operation_obj)
      end.flatten
    else
      yield *handle_merge(data_obj, operation_obj)
    end
  end
end

.value_from_dataset(dataset, key) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rulix/base.rb', line 71

def self.value_from_dataset dataset, key
  # Not a fan of type-checking here, would rather do a :respond_to? :[]
  # However, that scenario breaks when validating sensitive data
  # on an ActiveRecord model (like password) or any other attribute
  # that is manipulated in the biz logic layer before being set on
  # the db (e.g.: Model(:ssn) -> Database(:encrypted_ssn))
  if dataset.is_a? Hash
    dataset[key]
  else
    dataset.public_send(key)
  end
end