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



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

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



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

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



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

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



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

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



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

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



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

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
72
73
# 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::WEB_CAMPAIGN_VARIATION
    SegmentOperandEvaluator.new.evaluate_web_testing_campaign_variation_dsl(sub_dsl, @context)
  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



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

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



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
118
119
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 79

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



211
212
213
# File 'lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb', line 211

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