Module: Ruby::Rego::Unifier::Helpers

Defined in:
lib/ruby/rego/unifier.rb

Overview

Internal helpers that do not rely on instance state.

Class Method Summary collapse

Class Method Details

.bind_key_variable(key_pattern, candidate_key, bindings, env) ⇒ Object

:reek:LongParameterList :reek:TooManyStatements



143
144
145
146
147
148
149
150
151
152
153
# File 'lib/ruby/rego/unifier.rb', line 143

def self.bind_key_variable(key_pattern, candidate_key, bindings, env)
  return bindings unless key_pattern.is_a?(AST::Variable)

  name = key_pattern.name
  return bindings if name == "_"

  bound_value = bound_value_for(name, bindings, env)
  return bindings if bound_value

  merge_bindings(bindings, name => Value.from_ruby(candidate_key))
end

.bound_value_for(name, bindings, env) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/ruby/rego/unifier.rb', line 83

def self.bound_value_for(name, bindings, env)
  bound = bindings[name]
  return bound if bound && !bound.is_a?(UndefinedValue)

  env_value = env.lookup(name)
  return nil if env_value.is_a?(UndefinedValue)

  env_value
end

.candidate_keys_for(key_pattern, keys, env, bindings) ⇒ Object

:reek:TooManyStatements :reek:LongParameterList



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/ruby/rego/unifier.rb', line 117

def self.candidate_keys_for(key_pattern, keys, env, bindings)
  if key_pattern.is_a?(AST::Variable)
    name = key_pattern.name
    return keys if name == "_"

    bound_value = bound_value_for(name, bindings, env)
    return [normalize_key(bound_value.to_ruby)] if bound_value

    return keys
  end

  key_value = value_for_pattern(key_pattern, env)
  return [] if key_value.is_a?(UndefinedValue)

  [normalize_key(key_value.to_ruby)]
end

.match_scalar(pattern, resolved_value, env, bindings) ⇒ Object

:reek:LongParameterList :reek:ControlParameter



136
137
138
139
# File 'lib/ruby/rego/unifier.rb', line 136

def self.match_scalar(pattern, resolved_value, env, bindings)
  pattern_value = scalar_pattern_value(pattern, env)
  pattern_value == resolved_value ? [bindings] : []
end

.merge_bindings(bindings, additions) ⇒ Object



93
94
95
96
97
98
99
100
101
# File 'lib/ruby/rego/unifier.rb', line 93

def self.merge_bindings(bindings, additions)
  conflict = additions.any? do |name, value|
    existing = bindings[name]
    existing && existing != value
  end
  return nil if conflict

  bindings.merge(additions)
end

.normalize_array(value) ⇒ Object



39
40
41
42
43
44
# File 'lib/ruby/rego/unifier.rb', line 39

def self.normalize_array(value)
  return normalize_elements(value.to_ruby) if value.is_a?(ArrayValue)
  return normalize_elements(value) if value.is_a?(Array)

  nil
end

.normalize_elements(elements) ⇒ Object



46
47
48
49
50
51
52
53
54
# File 'lib/ruby/rego/unifier.rb', line 46

def self.normalize_elements(elements)
  values = [] # @type var values: Array[Value]
  elements.each do |element|
    values << Value.from_ruby(element)
  rescue ArgumentError, ObjectKeyConflictError
    return nil
  end
  values
end

.normalize_key(key) ⇒ Object



56
57
58
# File 'lib/ruby/rego/unifier.rb', line 56

def self.normalize_key(key)
  key.is_a?(Symbol) ? key.to_s : key
end

.normalize_object(value) ⇒ Object

:reek:TooManyStatements



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/ruby/rego/unifier.rb', line 68

def self.normalize_object(value)
  return nil unless (pairs = object_pairs(value))

  values = {} # @type var values: Hash[Object, Value]
  pairs.each do |key, val|
    normalized_key = normalize_key(key)
    return nil if values.key?(normalized_key)

    values[normalized_key] = Value.from_ruby(val)
  end
  values
rescue ArgumentError, ObjectKeyConflictError
  nil
end

.normalize_value(value, env) ⇒ Object



25
26
27
28
29
30
31
32
33
# File 'lib/ruby/rego/unifier.rb', line 25

def self.normalize_value(value, env)
  return value if value.is_a?(Value)
  return env.resolve_reference(value) if value.is_a?(AST::Reference)
  return Value.from_ruby(value.value) if value.is_a?(AST::Literal)

  Value.from_ruby(value)
rescue ArgumentError, ObjectKeyConflictError
  UndefinedValue.new
end

.object_pairs(value) ⇒ Object



60
61
62
63
64
65
# File 'lib/ruby/rego/unifier.rb', line 60

def self.object_pairs(value)
  return value.to_ruby if value.is_a?(ObjectValue)
  return value if value.is_a?(Hash)

  nil
end

.scalar_pattern_value(pattern, env) ⇒ Object



15
16
17
18
19
20
21
22
23
# File 'lib/ruby/rego/unifier.rb', line 15

def self.scalar_pattern_value(pattern, env)
  return Value.from_ruby(pattern.value) if pattern.is_a?(AST::Literal)
  return env.resolve_reference(pattern) if pattern.is_a?(AST::Reference)
  return pattern if pattern.is_a?(Value)

  Value.from_ruby(pattern)
rescue ArgumentError, ObjectKeyConflictError
  UndefinedValue.new
end

.unify_variable(variable, value, env, bindings) ⇒ Object

:reek:LongParameterList :reek:TooManyStatements



105
106
107
108
109
110
111
112
113
# File 'lib/ruby/rego/unifier.rb', line 105

def self.unify_variable(variable, value, env, bindings)
  name = variable.name
  return [bindings] if name == "_"

  bound_value = bound_value_for(name, bindings, env)
  return bound_value == value ? [bindings] : [] if bound_value

  [bindings.merge(name => value)]
end

.value_for_pattern(pattern, env) ⇒ Object



35
36
37
# File 'lib/ruby/rego/unifier.rb', line 35

def self.value_for_pattern(pattern, env)
  Helpers.scalar_pattern_value(pattern, env)
end