Class: Context

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(clock, config, data_future, data_provider, event_handler, event_logger, variable_parser, audience_matcher) ⇒ Context

Returns a new instance of Context.



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
# File 'lib/context.rb', line 21

def initialize(clock, config, data_future, data_provider,
               event_handler, event_logger, variable_parser, audience_matcher)
  @index = []
  @context_custom_fields = {}
  @achievements = []
  @assignment_cache = {}
  @assignments = {}
  @clock = clock.is_a?(String) ? Time.iso8601(clock) : clock
  @publish_delay = config.publish_delay
  @refresh_interval = config.refresh_interval
  @event_handler = event_handler
  @event_logger = !config.event_logger.nil? ? config.event_logger : event_logger
  @data_provider = data_provider
  @variable_parser = variable_parser
  @audience_matcher = audience_matcher
  @closed = false

  @units = {}
  @attributes = []
  @overrides = {}
  @cassignments = {}
  @assigners = {}
  @hashed_units = {}
  @pending_count = 0
  @exposures ||= []
  @attrs_seq = 0

  set_units(config.units) if config.units
  set_attributes(config.attributes) if config.attributes
  set_overrides(config.overrides) if config.overrides
  set_custom_assignments(config.custom_assignments) if config.custom_assignments
  if data_future.success?
    assign_data(data_future.data_future)
    log_event(ContextEventLogger::EVENT_TYPE::READY, data_future.data_future)
  else
    set_data_failed(data_future.exception)
    log_error(data_future.exception)
  end
end

Instance Attribute Details

#dataObject

Returns the value of attribute data.



13
14
15
# File 'lib/context.rb', line 13

def data
  @data
end

#pending_countObject

Returns the value of attribute pending_count.



13
14
15
# File 'lib/context.rb', line 13

def pending_count
  @pending_count
end

Class Method Details

.create(clock, config, data_future, data_provider, event_handler, event_logger, variable_parser, audience_matcher) ⇒ Object



15
16
17
18
19
# File 'lib/context.rb', line 15

def self.create(clock, config, data_future, data_provider,
                event_handler, event_logger, variable_parser, audience_matcher)
  Context.new(clock, config, data_future, data_provider,
              event_handler, event_logger, variable_parser, audience_matcher)
end

Instance Method Details

#closeObject



302
303
304
305
306
307
308
309
310
# File 'lib/context.rb', line 302

def close
  unless @closed
    if @pending_count > 0
      flush
    end
    @closed = true
    log_event(ContextEventLogger::EVENT_TYPE::CLOSE, nil)
  end
end

#closed?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/context.rb', line 69

def closed?
  @closed
end

#custom_assignment(experiment_name) ⇒ Object



109
110
111
112
113
# File 'lib/context.rb', line 109

def custom_assignment(experiment_name)
  check_not_closed?

  @cassignments[experiment_name.to_s.to_sym]
end

#custom_field_keysObject



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/context.rb', line 211

def custom_field_keys
  check_ready?(true)
  keys = []

  @data.experiments.each do |experiment|
    custom_field_values = experiment.custom_field_values
    if custom_field_values != nil
      custom_field_values.each do |custom_field|
        keys.append(custom_field.name)
      end
    end
  end

  return keys.sort.uniq
end

#custom_field_type(experimentName, key) ⇒ Object



242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/context.rb', line 242

def custom_field_type(experimentName, key)
  check_ready?(true)

  experiment_custom_fields = @context_custom_fields[experimentName]

  if experiment_custom_fields != nil
    field = experiment_custom_fields[key]
    if field != nil
      return field.type
    end
  end

  return nil
end

#custom_field_value(experimentName, key) ⇒ Object



227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/context.rb', line 227

def custom_field_value(experimentName, key)
  check_ready?(true)

  experiment_custom_fields = @context_custom_fields[experimentName]

  if experiment_custom_fields != nil
    field = experiment_custom_fields[key]
    if field != nil
      return field.value
    end
  end

  return nil
end

#experimentsObject



73
74
75
76
77
# File 'lib/context.rb', line 73

def experiments
  check_ready?(true)

  @data.experiments.map(&:name)
end

#failed?Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/context.rb', line 65

def failed?
  @failed
end

#override(experiment_name) ⇒ Object



91
92
93
94
95
# File 'lib/context.rb', line 91

def override(experiment_name)
  check_not_closed?

  @overrides[experiment_name.to_s.to_sym]
end

#peek_treatment(experiment_name) ⇒ Object Also known as: peek



183
184
185
186
187
# File 'lib/context.rb', line 183

def peek_treatment(experiment_name)
  check_ready?(true)

  assignment(experiment_name).variant
end

#peek_variable_value(key, default_value) ⇒ Object



257
258
259
260
261
262
263
264
265
266
# File 'lib/context.rb', line 257

def peek_variable_value(key, default_value)
  check_ready?(true)

  assignment = variable_assignment(key)
  return assignment.variables[key.to_s.to_sym] if !assignment.nil? &&
    !assignment.variables.nil? &&
    assignment.variables.key?(key.to_s.to_sym)

  default_value
end

#publishObject



281
282
283
284
285
# File 'lib/context.rb', line 281

def publish
  check_not_closed?

  flush
end

#queue_exposure(assignment) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/context.rb', line 160

def queue_exposure(assignment)
  unless assignment.exposed
    assignment.exposed = true

    exposure = Exposure.new
    exposure.id = assignment.id || 0
    exposure.name = assignment.name
    exposure.unit = assignment.unit_type
    exposure.variant = assignment.variant
    exposure.exposed_at = @clock.to_i
    exposure.assigned = assignment.assigned
    exposure.eligible = assignment.eligible
    exposure.overridden = assignment.overridden
    exposure.full_on = assignment.full_on
    exposure.custom = assignment.custom
    exposure.audience_mismatch = assignment.audience_mismatch

    @pending_count += 1
    @exposures.push(exposure)
    log_event(ContextEventLogger::EVENT_TYPE::EXPOSURE, exposure)
  end
end

#ready?Boolean

Returns:

  • (Boolean)


61
62
63
# File 'lib/context.rb', line 61

def ready?
  !@data.nil?
end

#refreshObject



287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/context.rb', line 287

def refresh
  check_not_closed?

  unless @failed
    data_future = @data_provider.context_data
    if data_future.success?
      assign_data(data_future.data_future)
      log_event(ContextEventLogger::EVENT_TYPE::REFRESH, data_future.data_future)
    else
      set_data_failed(data_future.exception)
      log_error(data_future.exception)
    end
  end
end

#set_attribute(name, value) ⇒ Object



137
138
139
140
141
142
# File 'lib/context.rb', line 137

def set_attribute(name, value)
  check_not_closed?

  @attributes.push(Attribute.new(name, value, @clock.to_i))
  @attrs_seq += 1
end

#set_attributes(attributes) ⇒ Object



144
145
146
147
148
# File 'lib/context.rb', line 144

def set_attributes(attributes)
  check_not_closed?

  attributes.each { |key, value| self.set_attribute(key, value) }
end

#set_custom_assignment(experiment_name, variant) ⇒ Object



97
98
99
100
101
# File 'lib/context.rb', line 97

def set_custom_assignment(experiment_name, variant)
  check_not_closed?

  @cassignments[experiment_name.to_s.to_sym] = variant
end

#set_custom_assignments(custom_assignments) ⇒ Object



103
104
105
106
107
# File 'lib/context.rb', line 103

def set_custom_assignments(custom_assignments)
  check_not_closed?

  @cassignments.merge!(custom_assignments.transform_keys(&:to_sym))
end

#set_override(experiment_name, variant) ⇒ Object



79
80
81
82
83
# File 'lib/context.rb', line 79

def set_override(experiment_name, variant)
  check_not_closed?

  @overrides[experiment_name.to_s.to_sym] = variant
end

#set_overrides(overrides) ⇒ Object



85
86
87
88
89
# File 'lib/context.rb', line 85

def set_overrides(overrides)
  check_not_closed?

  @overrides.merge!(overrides.transform_keys(&:to_sym))
end

#set_unit(unit_type, uid) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/context.rb', line 115

def set_unit(unit_type, uid)
  check_not_closed?

  previous = @units[unit_type.to_sym]
  if !previous.nil? && previous != uid
    raise IllegalStateException.new("Unit '#{unit_type}' already set.")
  end

  trimmed = uid.to_s.strip
  if trimmed.empty?
    raise IllegalStateException.new("Unit '#{unit_type}' UID must not be blank.")
  end

  @units[unit_type] = trimmed
end

#set_units(units) ⇒ Object



131
132
133
134
135
# File 'lib/context.rb', line 131

def set_units(units)
  check_not_closed?

  units.each { |key, value| self.set_unit(key, value) }
end

#track(goal_name, properties) ⇒ Object



268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/context.rb', line 268

def track(goal_name, properties)
  check_not_closed?

  achievement = GoalAchievement.new
  achievement.achieved_at = @clock.to_i
  achievement.name = goal_name
  achievement.properties = properties

  @pending_count += 1
  @achievements.push(achievement)
  log_event(ContextEventLogger::EVENT_TYPE::GOAL, achievement)
end

#treatment(experiment_name) ⇒ Object



150
151
152
153
154
155
156
157
158
# File 'lib/context.rb', line 150

def treatment(experiment_name)
  check_ready?(true)
  assignment = assignment(experiment_name)
  unless assignment.exposed
    queue_exposure(assignment)
  end

  assignment.variant
end

#variable_keysObject



191
192
193
194
195
196
197
# File 'lib/context.rb', line 191

def variable_keys
  check_ready?(true)

  hsh = {}
  @index_variables.each { |key, value| hsh[key] = value.data.name }
  hsh
end

#variable_value(key, default_value) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
# File 'lib/context.rb', line 199

def variable_value(key, default_value)
  check_ready?(true)

  assignment = variable_assignment(key)
  unless assignment.nil? || assignment.variables.nil?
    queue_exposure(assignment) unless assignment.exposed
    return assignment.variables[key.to_s.to_sym] if assignment.variables.key?(key.to_s.to_sym)
  end

  default_value
end