Class: Unleash::Constraint

Inherits:
Object
  • Object
show all
Defined in:
lib/unleash/constraint.rb

Constant Summary collapse

OPERATORS =
{
  IN: ->(context_v, constraint_v){ constraint_v.include? context_v.to_s },
  NOT_IN: ->(context_v, constraint_v){ !constraint_v.include? context_v.to_s },
  STR_STARTS_WITH: ->(context_v, constraint_v){ constraint_v.any?{ |v| context_v.start_with? v } },
  STR_ENDS_WITH: ->(context_v, constraint_v){ constraint_v.any?{ |v| context_v.end_with? v } },
  STR_CONTAINS: ->(context_v, constraint_v){ constraint_v.any?{ |v| context_v.include? v } },
  NUM_EQ: ->(context_v, constraint_v){ on_valid_float(constraint_v, context_v){ |x, y| (x - y).abs < Float::EPSILON } },
  NUM_LT: ->(context_v, constraint_v){ on_valid_float(constraint_v, context_v){ |x, y| (x > y) } },
  NUM_LTE: ->(context_v, constraint_v){ on_valid_float(constraint_v, context_v){ |x, y| (x >= y) } },
  NUM_GT: ->(context_v, constraint_v){ on_valid_float(constraint_v, context_v){ |x, y| (x < y) } },
  NUM_GTE: ->(context_v, constraint_v){ on_valid_float(constraint_v, context_v){ |x, y| (x <= y) } },
  DATE_AFTER: ->(context_v, constraint_v){ on_valid_date(constraint_v, context_v){ |x, y| (x < y) } },
  DATE_BEFORE: ->(context_v, constraint_v){ on_valid_date(constraint_v, context_v){ |x, y| (x > y) } },
  SEMVER_EQ: ->(context_v, constraint_v){ on_valid_version(constraint_v, context_v){ |x, y| (x == y) } },
  SEMVER_GT: ->(context_v, constraint_v){ on_valid_version(constraint_v, context_v){ |x, y| (x < y) } },
  SEMVER_LT: ->(context_v, constraint_v){ on_valid_version(constraint_v, context_v){ |x, y| (x > y) } },
  FALLBACK_VALIDATOR: ->(_context_v, _constraint_v){ false }
}.freeze
LIST_OPERATORS =
[:IN, :NOT_IN, :STR_STARTS_WITH, :STR_ENDS_WITH, :STR_CONTAINS].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context_name, operator, value = [], inverted: false, case_insensitive: false) ⇒ Constraint

Returns a new instance of Constraint.

Raises:

  • (ArgumentError)


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/unleash/constraint.rb', line 27

def initialize(context_name, operator, value = [], inverted: false, case_insensitive: false)
  raise ArgumentError, "context_name is not a String" unless context_name.is_a?(String)

  unless OPERATORS.include? operator.to_sym
    Unleash.logger.warn "Operator #{operator} is not a supported operator, " \
      "falling back to FALLBACK_VALIDATOR which skips this constraint."
    operator = "FALLBACK_VALIDATOR"
  end
  self.log_inconsistent_constraint_configuration(operator.to_sym, value)

  self.context_name = context_name
  self.operator = operator.to_sym
  self.value = value
  self.inverted = !!inverted
  self.case_insensitive = !!case_insensitive
end

Instance Attribute Details

#case_insensitiveObject

Returns the value of attribute case_insensitive.



4
5
6
# File 'lib/unleash/constraint.rb', line 4

def case_insensitive
  @case_insensitive
end

#context_nameObject

Returns the value of attribute context_name.



4
5
6
# File 'lib/unleash/constraint.rb', line 4

def context_name
  @context_name
end

#invertedObject

Returns the value of attribute inverted.



4
5
6
# File 'lib/unleash/constraint.rb', line 4

def inverted
  @inverted
end

#operatorObject

Returns the value of attribute operator.



4
5
6
# File 'lib/unleash/constraint.rb', line 4

def operator
  @operator
end

#valueObject

Returns the value of attribute value.



4
5
6
# File 'lib/unleash/constraint.rb', line 4

def value
  @value
end

Class Method Details

.on_valid_date(val1, val2) ⇒ Object



56
57
58
59
60
61
62
63
64
# File 'lib/unleash/constraint.rb', line 56

def self.on_valid_date(val1, val2)
  val1 = DateTime.parse(val1)
  val2 = DateTime.parse(val2)
  yield(val1, val2)
rescue ArgumentError
  Unleash.logger.warn "Unleash::ConstraintMatcher unable to parse either context_value (#{val1}) \
  or constraint_value (#{val2}) into a date. Returning false!"
  false
end

.on_valid_float(val1, val2) ⇒ Object



66
67
68
69
70
71
72
73
74
# File 'lib/unleash/constraint.rb', line 66

def self.on_valid_float(val1, val2)
  val1 = Float(val1)
  val2 = Float(val2)
  yield(val1, val2)
rescue ArgumentError
  Unleash.logger.warn "Unleash::ConstraintMatcher unable to parse either context_value (#{val1}) \
  or constraint_value (#{val2}) into a number. Returning false!"
  false
end

.on_valid_version(val1, val2) ⇒ Object



76
77
78
79
80
81
82
83
84
# File 'lib/unleash/constraint.rb', line 76

def self.on_valid_version(val1, val2)
  val1 = Gem::Version.new(val1)
  val2 = Gem::Version.new(val2)
  yield(val1, val2)
rescue ArgumentError
  Unleash.logger.warn "Unleash::ConstraintMatcher unable to parse either context_value (#{val1}) \
  or constraint_value (#{val2}) into a version. Return false!"
  false
end

Instance Method Details

#log_inconsistent_constraint_configuration(operator, value) ⇒ Object

This should be a private method but for some reason this fails on Ruby 2.5



87
88
89
90
# File 'lib/unleash/constraint.rb', line 87

def log_inconsistent_constraint_configuration(operator, value)
  Unleash.logger.warn "value is a String, operator is expecting an Array" if LIST_OPERATORS.include?(operator) && value.is_a?(String)
  Unleash.logger.warn "value is an Array, operator is expecting a String" if !LIST_OPERATORS.include?(operator) && value.is_a?(Array)
end

#matches_context?(context) ⇒ Boolean

Returns:

  • (Boolean)


44
45
46
47
48
49
50
51
52
53
54
# File 'lib/unleash/constraint.rb', line 44

def matches_context?(context)
  Unleash.logger.debug "Unleash::Constraint matches_context? value: #{self.value} context.get_by_name(#{self.context_name})"
  return false if context.nil?

  match = matches_constraint?(context)
  self.inverted ? !match : match
rescue KeyError
  Unleash.logger.warn "Attemped to resolve a context key during constraint resolution: #{self.context_name} but it wasn't \
  found on the context"
  false
end