Module: LaunchDarkly::Impl::EvaluatorOperators

Defined in:
lib/ldclient-rb/impl/evaluator_operators.rb

Overview

Defines the behavior of all operators that can be used in feature flag rules and segment rules.

Since:

  • 5.5.0

Class Method Summary collapse

Class Method Details

.add_zero_version_component(v) ⇒ Object

Since:

  • 5.5.0



124
125
126
127
128
# File 'lib/ldclient-rb/impl/evaluator_operators.rb', line 124

def self.add_zero_version_component(v)
  NUMERIC_VERSION_COMPONENTS_REGEX.match(v) { |m|
    m[0] + ".0" + v[m[0].length..-1]
  }
end

.apply(op, context_value, clause_value) ⇒ Boolean

Applies an operator to produce a boolean result.

Parameters:

  • op (Symbol)

    one of the supported LaunchDarkly operators, as a symbol

  • context_value

    the value of the context attribute that is referenced in the current clause (left-hand side of the expression)

  • clause_value

    the constant value that ‘context_value` is being compared to (right-hand side of the expression)

Returns:

  • (Boolean)

    true if the expression should be considered a match; false if it is not a match, or if the values cannot be compared because they are of the wrong types, or if the operator is unknown

Since:

  • 5.5.0



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/ldclient-rb/impl/evaluator_operators.rb', line 18

def self.apply(op, context_value, clause_value)
  case op
  when :in
    context_value == clause_value
  when :startsWith
    string_op(context_value, clause_value, lambda { |a, b| a.start_with? b })
  when :endsWith
    string_op(context_value, clause_value, lambda { |a, b| a.end_with? b })
  when :contains
    string_op(context_value, clause_value, lambda { |a, b| a.include? b })
  when :matches
    string_op(context_value, clause_value, lambda { |a, b|
      begin
        re = Regexp.new b
        !re.match(a).nil?
      rescue
        false
      end
    })
  when :lessThan
    numeric_op(context_value, clause_value, lambda { |a, b| a < b })
  when :lessThanOrEqual
    numeric_op(context_value, clause_value, lambda { |a, b| a <= b })
  when :greaterThan
    numeric_op(context_value, clause_value, lambda { |a, b| a > b })
  when :greaterThanOrEqual
    numeric_op(context_value, clause_value, lambda { |a, b| a >= b })
  when :before
    date_op(context_value, clause_value, lambda { |a, b| a < b })
  when :after
    date_op(context_value, clause_value, lambda { |a, b| a > b })
  when :semVerEqual
    semver_op(context_value, clause_value, lambda { |a, b| a == b })
  when :semVerLessThan
    semver_op(context_value, clause_value, lambda { |a, b| a < b })
  when :semVerGreaterThan
    semver_op(context_value, clause_value, lambda { |a, b| a > b })
  when :segmentMatch
    # We should never reach this; it can't be evaluated based on just two parameters, because it requires
    # looking up the segment from the data store. Instead, we special-case this operator in clause_match_context.
    false
  else
    false
  end
end

.date_op(context_value, clause_value, fn) ⇒ Object

Since:

  • 5.5.0



77
78
79
80
81
82
83
84
85
# File 'lib/ldclient-rb/impl/evaluator_operators.rb', line 77

def self.date_op(context_value, clause_value, fn)
  ud = to_date(context_value)
  if !ud.nil?
    cd = to_date(clause_value)
    !cd.nil? && fn.call(ud, cd)
  else
    false
  end
end

.numeric_op(context_value, clause_value, fn) ⇒ Object

Since:

  • 5.5.0



73
74
75
# File 'lib/ldclient-rb/impl/evaluator_operators.rb', line 73

def self.numeric_op(context_value, clause_value, fn)
  (context_value.is_a? Numeric) && (clause_value.is_a? Numeric) && fn.call(context_value, clause_value)
end

.semver_op(context_value, clause_value, fn) ⇒ Object

Since:

  • 5.5.0



87
88
89
90
91
92
93
94
95
# File 'lib/ldclient-rb/impl/evaluator_operators.rb', line 87

def self.semver_op(context_value, clause_value, fn)
  uv = to_semver(context_value)
  if !uv.nil?
    cv = to_semver(clause_value)
    !cv.nil? && fn.call(uv, cv)
  else
    false
  end
end

.string_op(context_value, clause_value, fn) ⇒ Object

Since:

  • 5.5.0



69
70
71
# File 'lib/ldclient-rb/impl/evaluator_operators.rb', line 69

def self.string_op(context_value, clause_value, fn)
  (context_value.is_a? String) && (clause_value.is_a? String) && fn.call(context_value, clause_value)
end

.to_date(value) ⇒ Object

Since:

  • 5.5.0



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ldclient-rb/impl/evaluator_operators.rb', line 97

def self.to_date(value)
  if value.is_a? String
    begin
      DateTime.rfc3339(value).strftime("%Q").to_i
    rescue => e
      nil
    end
  elsif value.is_a? Numeric
    value
  else
    nil
  end
end

.to_semver(value) ⇒ Object

Since:

  • 5.5.0



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/ldclient-rb/impl/evaluator_operators.rb', line 111

def self.to_semver(value)
  if value.is_a? String
    for _ in 0..2 do
      begin
        return Semantic::Version.new(value)
      rescue ArgumentError
        value = add_zero_version_component(value)
      end
    end
  end
  nil
end