Class: TrailGuide::Participant
- Inherits:
-
Object
- Object
- TrailGuide::Participant
- Defined in:
- lib/trail_guide/participant.rb
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
Instance Method Summary collapse
- #active_experiments(include_control = true) ⇒ Object
- #adapter ⇒ Object
- #cleanup_inactive_experiments! ⇒ Object
- #converted!(variant, checkpoint = nil, reset: false) ⇒ Object
- #converted?(experiment, checkpoint = nil) ⇒ Boolean
- #exit!(experiment) ⇒ Object
-
#initialize(context, adapter: nil) ⇒ Participant
constructor
A new instance of Participant.
- #participating!(variant) ⇒ Object
- #participating?(experiment, include_control = true) ⇒ Boolean
- #participating_in_active_experiments?(include_control = true) ⇒ Boolean
- #variant(experiment) ⇒ Object
Constructor Details
#initialize(context, adapter: nil) ⇒ Participant
Returns a new instance of Participant.
6 7 8 9 10 |
# File 'lib/trail_guide/participant.rb', line 6 def initialize(context, adapter: nil) @context = context @adapter = adapter.new(context) if adapter.present? cleanup_inactive_experiments! if TrailGuide.configuration.cleanup_participant_experiments end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
3 4 5 |
# File 'lib/trail_guide/participant.rb', line 3 def context @context end |
Instance Method Details
#active_experiments(include_control = true) ⇒ Object
116 117 118 119 120 121 122 123 |
# File 'lib/trail_guide/participant.rb', line 116 def active_experiments(include_control=true) return false if adapter.keys.empty? adapter.keys.map { |key| key.to_s.split(":").first.to_sym }.uniq.map do |key| experiment = TrailGuide.catalog.find(key) next unless experiment && !experiment.combined? && experiment.running? && participating?(experiment, include_control) [ experiment.experiment_name, adapter[experiment.storage_key] ] end.compact.to_h end |
#adapter ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/trail_guide/participant.rb', line 12 def adapter @adapter ||= begin config_adapter = TrailGuide.configuration.adapter case config_adapter when :cookie config_adapter = TrailGuide::Adapters::Participants::Cookie when :session config_adapter = TrailGuide::Adapters::Participants::Session when :redis config_adapter = TrailGuide::Adapters::Participants::Redis when :anonymous config_adapter = TrailGuide::Adapters::Participants::Anonymous when :multi config_adapter = TrailGuide::Adapters::Participants::Multi else config_adapter = config_adapter.constantize if config_adapter.is_a?(String) end config_adapter.new(context) rescue => e [TrailGuide.configuration.on_adapter_failover].flatten.compact.each do |callback| callback.call(config_adapter, e) end TrailGuide::Adapters::Participants::Anonymous.new(context) end end |
#cleanup_inactive_experiments! ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/trail_guide/participant.rb', line 135 def cleanup_inactive_experiments! return false if adapter.keys.empty? adapter.keys.each do |key| experiment_name = key.to_s.split(":").first.to_sym experiment = TrailGuide.catalog.find(experiment_name) if !experiment || !experiment.started? adapter.delete(key) end end return true end |
#converted!(variant, checkpoint = nil, reset: false) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/trail_guide/participant.rb', line 88 def converted!(variant, checkpoint=nil, reset: false) checkpoint ||= :converted storage_key = "#{variant.experiment.storage_key}:#{checkpoint.to_s.underscore}" if reset adapter.delete(variant.experiment.storage_key) adapter.delete(variant.storage_key) adapter.delete(storage_key) variant.experiment.goals.each do |goal| goal_key = "#{variant.experiment.storage_key}:#{goal.to_s}" adapter.delete(goal_key) end else adapter[storage_key] = Time.now.to_i end end |
#converted?(experiment, checkpoint = nil) ⇒ Boolean
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/trail_guide/participant.rb', line 56 def converted?(experiment, checkpoint=nil) return false unless experiment.started? if experiment.goals.empty? raise InvalidGoalError, "You provided the checkpoint `#{checkpoint}` but the experiment `#{experiment.experiment_name}` does not have any goals defined." unless checkpoint.nil? storage_key = "#{experiment.storage_key}:converted" return false unless adapter.key?(storage_key) converted_at = Time.at(adapter[storage_key].to_i) converted_at >= experiment.started_at elsif !checkpoint.nil? raise InvalidGoalError, "Invalid goal checkpoint `#{checkpoint}` for experiment `#{experiment.experiment_name}`." unless experiment.goals.any? { |goal| goal == checkpoint.to_s.underscore.to_sym } storage_key = "#{experiment.storage_key}:#{checkpoint.to_s.underscore}" return false unless adapter.key?(storage_key) converted_at = Time.at(adapter[storage_key].to_i) converted_at >= experiment.started_at else experiment.goals.each do |goal| storage_key = "#{experiment.storage_key}:#{goal.to_s}" next unless adapter.key?(storage_key) converted_at = Time.at(adapter[storage_key].to_i) return true if converted_at >= experiment.started_at end return false end end |
#exit!(experiment) ⇒ Object
105 106 107 108 109 110 111 112 113 114 |
# File 'lib/trail_guide/participant.rb', line 105 def exit!(experiment) chosen = variant(experiment) return true if chosen.nil? adapter.delete(experiment.storage_key) adapter.delete(chosen.storage_key) experiment.goals.each do |goal| adapter.delete("#{experiment.storage_key}:#{goal.to_s}") end return true end |
#participating!(variant) ⇒ Object
83 84 85 86 |
# File 'lib/trail_guide/participant.rb', line 83 def participating!(variant) adapter[variant.experiment.storage_key] = variant.name adapter[variant.storage_key] = Time.now.to_i end |
#participating?(experiment, include_control = true) ⇒ Boolean
49 50 51 52 53 54 |
# File 'lib/trail_guide/participant.rb', line 49 def participating?(experiment, include_control=true) var = variant(experiment) return false if var.nil? return false if !include_control && var.control? return true end |
#participating_in_active_experiments?(include_control = true) ⇒ Boolean
125 126 127 128 129 130 131 132 133 |
# File 'lib/trail_guide/participant.rb', line 125 def participating_in_active_experiments?(include_control=true) return false if adapter.keys.empty? adapter.keys.any? do |key| experiment_name = key.to_s.split(":").first.to_sym experiment = TrailGuide.catalog.find(experiment_name) experiment && !experiment.combined? && experiment.running? && participating?(experiment, include_control) end end |
#variant(experiment) ⇒ Object
38 39 40 41 42 43 44 45 46 47 |
# File 'lib/trail_guide/participant.rb', line 38 def variant(experiment) return nil unless experiment.started? return nil unless adapter.key?(experiment.storage_key) varname = adapter[experiment.storage_key] variant = experiment.variants.find { |var| var == varname } return nil unless variant && adapter.key?(variant.storage_key) chosen_at = Time.at(adapter[variant.storage_key].to_i) return variant if chosen_at >= experiment.started_at end |