Class: SegmentEvaluator

Inherits:
Object
  • Object
show all
Defined in:
lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context = nil, settings = nil, feature = nil) ⇒ SegmentEvaluator

Returns a new instance of SegmentEvaluator.



32
33
34
35
36
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 32

def initialize(context = nil, settings = nil, feature = nil)
  @context = context
  @settings = settings
  @feature = feature
end

Instance Attribute Details

#contextObject

Returns the value of attribute context.



30
31
32
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 30

def context
  @context
end

#featureObject

Returns the value of attribute feature.



30
31
32
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 30

def feature
  @feature
end

#settingsObject

Returns the value of attribute settings.



30
31
32
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 30

def settings
  @settings
end

Instance Method Details

#add_location_values_to_map(dsl, location_map) ⇒ Object

Adds the location values to the map

Parameters:

  • dsl (Hash)

    The DSL node

  • location_map (Hash)

    The location map



140
141
142
143
144
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 140

def add_location_values_to_map(dsl, location_map)
  location_map[SegmentOperatorValueEnum::COUNTRY] = dsl[SegmentOperatorValueEnum::COUNTRY] if dsl.key?(SegmentOperatorValueEnum::COUNTRY)
  location_map[SegmentOperatorValueEnum::REGION] = dsl[SegmentOperatorValueEnum::REGION] if dsl.key?(SegmentOperatorValueEnum::REGION)
  location_map[SegmentOperatorValueEnum::CITY] = dsl[SegmentOperatorValueEnum::CITY] if dsl.key?(SegmentOperatorValueEnum::CITY)
end

#check_in_user_storage(settings, feature_key, context) ⇒ Boolean

Checks if the feature key is present in the user’s storage

Parameters:

  • settings (SettingsModel)

    The settings for the VWO instance

  • feature_key (String)

    The key of the feature to check

  • context (ContextModel)

    The context for the evaluation

Returns:

  • (Boolean)

    True if the feature key is present in the user’s storage, false otherwise



183
184
185
186
187
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 183

def check_in_user_storage(settings, feature_key, context)
  storage_service = StorageService.new
  stored_data = StorageDecorator.new.get_feature_from_storage(feature_key, context, storage_service)
  stored_data.is_a?(Hash) && !stored_data.empty?
end

#check_location_pre_segmentation(location_map) ⇒ Boolean

Checks if the location pre-segmentation is valid

Parameters:

  • location_map (Hash)

    The location map

Returns:

  • (Boolean)

    True if the location pre-segmentation is valid, false otherwise



149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 149

def check_location_pre_segmentation(location_map)
  unless @context&.get_ip_address
    LoggerService.log(LogLevelEnum::ERROR, 'INVALID_IP_ADDRESS_IN_CONTEXT_FOR_PRE_SEGMENTATION', { an: ApiEnum::GET_FLAG, sId: @context.get_session_id, uuid: @context.get_uuid})
    return false
  end
  
  unless @context&.get_vwo&.get_location
    return false
  end

  values_match(location_map, @context.get_vwo.get_location)
end

#check_user_agent_parser(ua_parser_map) ⇒ Boolean

Checks if the user agent parser is valid

Parameters:

  • ua_parser_map (Hash)

    The user agent parser map

Returns:

  • (Boolean)

    True if the user agent parser is valid, false otherwise



165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 165

def check_user_agent_parser(ua_parser_map)
  unless @context&.get_user_agent
    LoggerService.log(LogLevelEnum::ERROR, 'INVALID_USER_AGENT_IN_CONTEXT_FOR_PRE_SEGMENTATION', { an: ApiEnum::GET_FLAG, sId: @context.get_session_id, uuid: @context.get_uuid})
    return false
  end

  unless @context&.get_vwo&.get_ua_info
    return false
  end

  check_value_present(ua_parser_map, @context.get_vwo.get_ua_info)
end

#check_value_present(expected_map, actual_map) ⇒ Boolean

Checks if the expected values are present in the actual values

Parameters:

  • expected_map (Hash)

    The expected values

  • actual_map (Hash)

    The actual values

Returns:

  • (Boolean)

    True if the expected values are present in the actual values, false otherwise



193
194
195
196
197
198
199
200
201
202
203
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 193

def check_value_present(expected_map, actual_map)
  actual_map.each do |key, actual_value|
    next unless expected_map.key?(key)

    expected_values = expected_map[key].map(&:downcase)

    return true if expected_values.any? { |val| val.start_with?('wildcard(') && val.end_with?(')') && actual_value.match?(Regexp.new(val[9..-2].gsub('*', '.*'), Regexp::IGNORECASE)) }
    return true if expected_values.include?(actual_value.downcase)
  end
  false
end

#every(dsl_nodes, custom_variables) ⇒ Boolean

Evaluates all DSL nodes using the AND logic.

Parameters:

  • dsl_nodes (Array<Hash>)

    The DSL nodes to evaluate

  • custom_variables (Hash)

    The custom variables

Returns:

  • (Boolean)

    True if all DSL nodes are valid, false otherwise



123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 123

def every(dsl_nodes, custom_variables)
  location_map = {}
  dsl_nodes.each do |dsl|
    if dsl.keys.any? { |key| [SegmentOperatorValueEnum::COUNTRY, SegmentOperatorValueEnum::REGION,
                              SegmentOperatorValueEnum::CITY].include?(key) }
      add_location_values_to_map(dsl, location_map)
      return check_location_pre_segmentation(location_map) if location_map.keys.length == dsl_nodes.length
      next
    end
    return false unless is_segmentation_valid(dsl, custom_variables)
  end
  true
end

#is_segmentation_valid(dsl, properties) ⇒ Boolean

Validates if the segmentation defined in the DSL is applicable based on the provided properties.

Parameters:

  • dsl (Hash)

    The DSL node to evaluate

  • properties (Hash)

    The properties to evaluate the DSL against

Returns:

  • (Boolean)

    True if the segmentation is valid, false otherwise



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 42

def is_segmentation_valid(dsl, properties)
  key_value = get_key_value(dsl)
  return false unless key_value

  operator = key_value[:key]
  sub_dsl = key_value[:value]

  case operator
  when SegmentOperatorValueEnum::NOT
    !is_segmentation_valid(sub_dsl, properties)
  when SegmentOperatorValueEnum::AND
    every(sub_dsl, properties)
  when SegmentOperatorValueEnum::OR
    some(sub_dsl, properties)
  when SegmentOperatorValueEnum::CUSTOM_VARIABLE
    SegmentOperandEvaluator.new.evaluate_custom_variable_dsl(sub_dsl, properties)
  when SegmentOperatorValueEnum::USER
    SegmentOperandEvaluator.new.evaluate_user_dsl(sub_dsl, properties)
  when SegmentOperatorValueEnum::UA
    SegmentOperandEvaluator.new.evaluate_user_agent_dsl(sub_dsl, @context)
  when SegmentOperatorValueEnum::IP
    SegmentOperandEvaluator.new.evaluate_string_operand_dsl(sub_dsl, @context, SegmentOperatorValueEnum::IP)
  when SegmentOperatorValueEnum::BROWSER_VERSION
    SegmentOperandEvaluator.new.evaluate_string_operand_dsl(sub_dsl, @context, SegmentOperatorValueEnum::BROWSER_VERSION)
  when SegmentOperatorValueEnum::OS_VERSION
    SegmentOperandEvaluator.new.evaluate_string_operand_dsl(sub_dsl, @context, SegmentOperatorValueEnum::OS_VERSION)
  else
    false
  end
end

#normalize_value(value) ⇒ Object



213
214
215
216
217
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 213

def normalize_value(value)
  return nil if value.nil?

  value.to_s.gsub(/^"|"$/, '').strip
end

#some(dsl_nodes, custom_variables) ⇒ Boolean

Evaluates if any of the DSL nodes are valid using the OR logic.

Parameters:

  • dsl_nodes (Array<Hash>)

    The DSL nodes to evaluate

  • custom_variables (Hash)

    The custom variables

Returns:

  • (Boolean)

    True if any of the DSL nodes are valid, false otherwise



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 77

def some(dsl_nodes, custom_variables)
  ua_parser_map = {}
  key_count = 0
  is_ua_parser = false

  dsl_nodes.each do |dsl|
    dsl.each do |key, value|
      if [SegmentOperatorValueEnum::OPERATING_SYSTEM, SegmentOperatorValueEnum::BROWSER_AGENT,
          SegmentOperatorValueEnum::DEVICE_TYPE, SegmentOperatorValueEnum::DEVICE].include?(key)
        is_ua_parser = true
        ua_parser_map[key] ||= []
        ua_parser_map[key] += Array(value).map(&:to_s)
        key_count += 1
      end

      if key == SegmentOperatorValueEnum::FEATURE_ID
        feature_id_object = dsl[key]
        feature_id_key = feature_id_object.keys.first
        feature_id_value = feature_id_object[feature_id_key]

        if %w[on off].include?(feature_id_value)
          feature = @settings.get_features.find { |f| f.get_id == feature_id_key.to_i }
          if feature
            feature_key = feature.get_key
            result = check_in_user_storage(@settings, feature_key, @context)
            return !result if feature_id_value == 'off'
            return result
          else
            LoggerService.log(LogLevelEnum::INFO, "Feature not found with featureIdKey: #{feature_id_key}", nil)
            return nil
          end
        end
      end
    end

    return check_user_agent_parser(ua_parser_map) if is_ua_parser && key_count == dsl_nodes.length
    return true if is_segmentation_valid(dsl, custom_variables)
  end

  false
end

#values_match(expected_location_map, user_location) ⇒ Boolean

Checks if the expected location values match the user’s location

Parameters:

  • expected_location_map (Hash)

    The expected location values

  • user_location (Hash)

    The user’s location values

Returns:

  • (Boolean)

    True if the expected location values match the user’s location, false otherwise



209
210
211
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 209

def values_match(expected_location_map, user_location)
  expected_location_map.all? { |key, value| normalize_value(value) == normalize_value(user_location[key]) }
end