hackle-ruby-sdk 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/hackle/client.rb +186 -87
- data/lib/hackle/config.rb +59 -17
- data/lib/hackle/decision.rb +113 -0
- data/lib/hackle/event.rb +89 -0
- data/lib/hackle/internal/clock/clock.rb +47 -0
- data/lib/hackle/internal/concurrent/executors.rb +20 -0
- data/lib/hackle/internal/concurrent/schedule/scheduler.rb +12 -0
- data/lib/hackle/internal/concurrent/schedule/timer_scheduler.rb +30 -0
- data/lib/hackle/internal/config/parameter_config.rb +50 -0
- data/lib/hackle/internal/core/hackle_core.rb +182 -0
- data/lib/hackle/{decision → internal/evaluation/bucketer}/bucketer.rb +17 -15
- data/lib/hackle/internal/evaluation/evaluator/contextual/contextual_evaluator.rb +29 -0
- data/lib/hackle/internal/evaluation/evaluator/delegating/delegating_evaluator.rb +26 -0
- data/lib/hackle/internal/evaluation/evaluator/evaluator.rb +117 -0
- data/lib/hackle/internal/evaluation/evaluator/experiment/experiment_evaluation_flow_factory.rb +67 -0
- data/lib/hackle/internal/evaluation/evaluator/experiment/experiment_evaluator.rb +172 -0
- data/lib/hackle/internal/evaluation/evaluator/experiment/experiment_flow_evaluator.rb +241 -0
- data/lib/hackle/internal/evaluation/evaluator/experiment/experiment_resolver.rb +166 -0
- data/lib/hackle/internal/evaluation/evaluator/remoteconfig/remote_config_determiner.rb +48 -0
- data/lib/hackle/internal/evaluation/evaluator/remoteconfig/remote_config_evaluator.rb +174 -0
- data/lib/hackle/internal/evaluation/flow/evaluation_flow.rb +49 -0
- data/lib/hackle/internal/evaluation/flow/flow_evaluator.rb +11 -0
- data/lib/hackle/internal/evaluation/match/condition/condition_matcher.rb +11 -0
- data/lib/hackle/internal/evaluation/match/condition/condition_matcher_factory.rb +53 -0
- data/lib/hackle/internal/evaluation/match/condition/experiment/experiment_condition_matcher.rb +29 -0
- data/lib/hackle/internal/evaluation/match/condition/experiment/experiment_evaluator_matcher.rb +135 -0
- data/lib/hackle/internal/evaluation/match/condition/segment/segment_condition_matcher.rb +67 -0
- data/lib/hackle/internal/evaluation/match/condition/user/user_condition_matcher.rb +44 -0
- data/lib/hackle/internal/evaluation/match/operator/operator_matcher.rb +185 -0
- data/lib/hackle/internal/evaluation/match/operator/operator_matcher_factory.rb +31 -0
- data/lib/hackle/internal/evaluation/match/target/target_matcher.rb +31 -0
- data/lib/hackle/internal/evaluation/match/value/value_matcher.rb +96 -0
- data/lib/hackle/internal/evaluation/match/value/value_matcher_factory.rb +28 -0
- data/lib/hackle/internal/evaluation/match/value/value_operator_matcher.rb +59 -0
- data/lib/hackle/internal/event/user_event.rb +187 -0
- data/lib/hackle/internal/event/user_event_dispatcher.rb +156 -0
- data/lib/hackle/internal/event/user_event_factory.rb +58 -0
- data/lib/hackle/internal/event/user_event_processor.rb +181 -0
- data/lib/hackle/internal/http/http.rb +28 -0
- data/lib/hackle/internal/http/http_client.rb +48 -0
- data/lib/hackle/internal/identifiers/identifier_builder.rb +67 -0
- data/lib/hackle/internal/logger/logger.rb +31 -0
- data/lib/hackle/internal/model/action.rb +57 -0
- data/lib/hackle/internal/model/bucket.rb +58 -0
- data/lib/hackle/internal/model/container.rb +47 -0
- data/lib/hackle/internal/model/decision_reason.rb +31 -0
- data/lib/hackle/{models → internal/model}/event_type.rb +5 -8
- data/lib/hackle/internal/model/experiment.rb +194 -0
- data/lib/hackle/internal/model/parameter_configuration.rb +19 -0
- data/lib/hackle/internal/model/remote_config_parameter.rb +76 -0
- data/lib/hackle/internal/model/sdk.rb +23 -0
- data/lib/hackle/internal/model/segment.rb +61 -0
- data/lib/hackle/internal/model/target.rb +203 -0
- data/lib/hackle/internal/model/target_rule.rb +19 -0
- data/lib/hackle/internal/model/targeting.rb +45 -0
- data/lib/hackle/internal/model/value_type.rb +75 -0
- data/lib/hackle/internal/model/variation.rb +27 -0
- data/lib/hackle/internal/model/version.rb +153 -0
- data/lib/hackle/internal/properties/properties_builder.rb +101 -0
- data/lib/hackle/internal/user/hackle_user.rb +74 -0
- data/lib/hackle/internal/user/hackle_user_resolver.rb +27 -0
- data/lib/hackle/internal/workspace/http_workspace_fetcher.rb +50 -0
- data/lib/hackle/internal/workspace/polling_workspace_fetcher.rb +62 -0
- data/lib/hackle/internal/workspace/workspace.rb +353 -0
- data/lib/hackle/internal/workspace/workspace_fetcher.rb +18 -0
- data/lib/hackle/remote_config.rb +55 -0
- data/lib/hackle/user.rb +124 -0
- data/lib/hackle/version.rb +1 -11
- data/lib/hackle.rb +4 -69
- metadata +123 -53
- data/.gitignore +0 -11
- data/.rspec +0 -2
- data/.travis.yml +0 -7
- data/Gemfile +0 -6
- data/README.md +0 -33
- data/Rakefile +0 -6
- data/hackle-ruby-sdk.gemspec +0 -29
- data/lib/hackle/decision/decider.rb +0 -69
- data/lib/hackle/events/event_dispatcher.rb +0 -96
- data/lib/hackle/events/event_processor.rb +0 -126
- data/lib/hackle/events/user_event.rb +0 -61
- data/lib/hackle/http/http.rb +0 -37
- data/lib/hackle/models/bucket.rb +0 -26
- data/lib/hackle/models/event.rb +0 -26
- data/lib/hackle/models/experiment.rb +0 -69
- data/lib/hackle/models/slot.rb +0 -22
- data/lib/hackle/models/user.rb +0 -24
- data/lib/hackle/models/variation.rb +0 -21
- data/lib/hackle/workspaces/http_workspace_fetcher.rb +0 -24
- data/lib/hackle/workspaces/polling_workspace_fetcher.rb +0 -47
- data/lib/hackle/workspaces/workspace.rb +0 -100
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Hackle
|
|
4
|
-
|
|
5
|
-
class UserEvent
|
|
6
|
-
|
|
7
|
-
# @!attribute [r] timestamp
|
|
8
|
-
# @return [Integer]
|
|
9
|
-
# @!attribute [r] user
|
|
10
|
-
# @return [User]
|
|
11
|
-
attr_reader :timestamp, :user
|
|
12
|
-
|
|
13
|
-
# @param user [User]
|
|
14
|
-
def initialize(user:)
|
|
15
|
-
@timestamp = UserEvent.generate_timestamp
|
|
16
|
-
@user = user
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class Exposure < UserEvent
|
|
20
|
-
|
|
21
|
-
# @!attribute [r] experiment
|
|
22
|
-
# @return [Experiment]
|
|
23
|
-
# @!attribute [r] variation
|
|
24
|
-
# @return [Variation]
|
|
25
|
-
attr_reader :experiment, :variation
|
|
26
|
-
|
|
27
|
-
# @param user [User]
|
|
28
|
-
# @param experiment [Experiment]
|
|
29
|
-
# @param variation [Variation]
|
|
30
|
-
def initialize(user:, experiment:, variation:)
|
|
31
|
-
super(user: user)
|
|
32
|
-
@experiment = experiment
|
|
33
|
-
@variation = variation
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class Track < UserEvent
|
|
39
|
-
|
|
40
|
-
# @!attribute [r] event_type
|
|
41
|
-
# @return [EventType]
|
|
42
|
-
# @!attribute [r] event
|
|
43
|
-
# @return [Event]
|
|
44
|
-
attr_reader :event_type, :event
|
|
45
|
-
|
|
46
|
-
# @param user [User]
|
|
47
|
-
# @param event_type [EventType]
|
|
48
|
-
# @param event [Event]
|
|
49
|
-
def initialize(user:, event_type:, event:)
|
|
50
|
-
super(user: user)
|
|
51
|
-
@event_type = event_type
|
|
52
|
-
@event = event
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# @return [Integer]
|
|
57
|
-
def self.generate_timestamp
|
|
58
|
-
(Time.now.to_f * 1000).to_i
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
data/lib/hackle/http/http.rb
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'net/http'
|
|
4
|
-
|
|
5
|
-
module Hackle
|
|
6
|
-
class UnexpectedResponseError < StandardError
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
class HTTP
|
|
10
|
-
def self.client(base_uri:)
|
|
11
|
-
uri = URI.parse(base_uri)
|
|
12
|
-
client = Net::HTTP.new(uri.host, uri.port)
|
|
13
|
-
client.use_ssl = uri.scheme == 'https'
|
|
14
|
-
client.open_timeout = 5
|
|
15
|
-
client.read_timeout = 10
|
|
16
|
-
client
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.sdk_headers(sdk_info:)
|
|
20
|
-
{
|
|
21
|
-
'X-HACKLE-SDK-KEY' => sdk_info.key,
|
|
22
|
-
'X-HACKLE-SDK-NAME' => sdk_info.name,
|
|
23
|
-
'X-HACKLE-SDK-VERSION' => sdk_info.version
|
|
24
|
-
}
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def self.successful?(status_code:)
|
|
28
|
-
status_code >= 200 && status_code < 300
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def self.check_successful(status_code:)
|
|
32
|
-
unless successful?(status_code: status_code)
|
|
33
|
-
raise UnexpectedResponseError, "HTTP status code #{status_code}"
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
data/lib/hackle/models/bucket.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
module Hackle
|
|
2
|
-
|
|
3
|
-
class Bucket
|
|
4
|
-
|
|
5
|
-
# @!attribute [r] seed
|
|
6
|
-
# @return [Integer]
|
|
7
|
-
# @!attribute [r] slot_size
|
|
8
|
-
# @return [Integer]
|
|
9
|
-
attr_reader :seed, :slot_size
|
|
10
|
-
|
|
11
|
-
# @param seed [Integer]
|
|
12
|
-
# @param slot_size [Integer]
|
|
13
|
-
# @param slots [Array]
|
|
14
|
-
def initialize(seed:, slot_size:, slots:)
|
|
15
|
-
@seed = seed
|
|
16
|
-
@slot_size = slot_size
|
|
17
|
-
@slots = slots
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# @param slot_number [Integer]
|
|
21
|
-
# @return [Slot, nil]
|
|
22
|
-
def get_slot(slot_number:)
|
|
23
|
-
@slots.find { |slot| slot.contains?(slot_number: slot_number) }
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
data/lib/hackle/models/event.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
module Hackle
|
|
2
|
-
class Event
|
|
3
|
-
|
|
4
|
-
# @!attribute [r] key
|
|
5
|
-
# @return [String]
|
|
6
|
-
# @!attribute [r] value
|
|
7
|
-
# @return [Float, nil]
|
|
8
|
-
# @!attribute [r] properties
|
|
9
|
-
# @return [Hash]
|
|
10
|
-
attr_reader :key, :value, :properties
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# @param key [String]
|
|
14
|
-
# @param value [Float, nil]
|
|
15
|
-
# @param properties [Hash{Symbol => String, Number, boolean}]
|
|
16
|
-
def initialize(key:, value:, properties:)
|
|
17
|
-
@key = key
|
|
18
|
-
@value = value
|
|
19
|
-
@properties = properties
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def valid?
|
|
23
|
-
!key.nil? && key.is_a?(String)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
module Hackle
|
|
2
|
-
class Experiment
|
|
3
|
-
|
|
4
|
-
# @!attribute [r] id
|
|
5
|
-
# @return [Integer]
|
|
6
|
-
# @!attribute [r] key
|
|
7
|
-
# @return [Integer]
|
|
8
|
-
attr_reader :id, :key
|
|
9
|
-
|
|
10
|
-
# @param id [Integer]
|
|
11
|
-
# @param key [Integer]
|
|
12
|
-
def initialize(id:, key:)
|
|
13
|
-
@id = id
|
|
14
|
-
@key = key
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
class Running < Experiment
|
|
18
|
-
|
|
19
|
-
# @!attribute [r] bucket
|
|
20
|
-
# @return [Bucket]
|
|
21
|
-
attr_reader :bucket
|
|
22
|
-
|
|
23
|
-
# @param id [Integer]
|
|
24
|
-
# @param key [Integer]
|
|
25
|
-
# @param bucket [Bucket]
|
|
26
|
-
# @param variations [Hash{String => Variation}]
|
|
27
|
-
# @param overrides [Hash{String => Integer}]
|
|
28
|
-
def initialize(id:, key:, bucket:, variations:, overrides:)
|
|
29
|
-
super(id: id, key: key)
|
|
30
|
-
@bucket = bucket
|
|
31
|
-
|
|
32
|
-
# @type [Hash{String => Variation}]
|
|
33
|
-
@variations = variations
|
|
34
|
-
|
|
35
|
-
# @type [Hash{String => Integer}]
|
|
36
|
-
@overrides = overrides
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# @param variation_id [Integer]
|
|
40
|
-
# @return [Variation, nil]
|
|
41
|
-
def get_variation(variation_id:)
|
|
42
|
-
@variations[variation_id]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# @param user [User]
|
|
46
|
-
# @return [Variation, nil]
|
|
47
|
-
def get_overridden_variation(user:)
|
|
48
|
-
overridden_variation_id = @overrides[user.id]
|
|
49
|
-
return nil if overridden_variation_id.nil?
|
|
50
|
-
get_variation(variation_id: overridden_variation_id)
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
class Completed < Experiment
|
|
55
|
-
|
|
56
|
-
# @!attribute [r] winner_variation_key
|
|
57
|
-
# @return [String]
|
|
58
|
-
attr_reader :winner_variation_key
|
|
59
|
-
|
|
60
|
-
# @param id [Integer]
|
|
61
|
-
# @param key [Integer]
|
|
62
|
-
# @param winner_variation_key [String]
|
|
63
|
-
def initialize(id:, key:, winner_variation_key:)
|
|
64
|
-
super(id: id, key: key)
|
|
65
|
-
@winner_variation_key = winner_variation_key
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
data/lib/hackle/models/slot.rb
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
module Hackle
|
|
2
|
-
class Slot
|
|
3
|
-
# @!attribute variation_id
|
|
4
|
-
# @return [Integer]
|
|
5
|
-
attr_reader :variation_id
|
|
6
|
-
|
|
7
|
-
# @param start_inclusive [Integer]
|
|
8
|
-
# @param end_exclusive [Integer]
|
|
9
|
-
# @param variation_id [Integer]
|
|
10
|
-
def initialize(start_inclusive:, end_exclusive:, variation_id:)
|
|
11
|
-
@start_inclusive = start_inclusive
|
|
12
|
-
@end_exclusive = end_exclusive
|
|
13
|
-
@variation_id = variation_id
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# @param slot_number [Integer]
|
|
17
|
-
# @return [boolean]
|
|
18
|
-
def contains?(slot_number:)
|
|
19
|
-
@start_inclusive <= slot_number && slot_number < @end_exclusive
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
data/lib/hackle/models/user.rb
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
module Hackle
|
|
2
|
-
|
|
3
|
-
class User
|
|
4
|
-
|
|
5
|
-
# @!attribute [r] id
|
|
6
|
-
# @return [String]
|
|
7
|
-
# @!attribute [r] properties
|
|
8
|
-
# @return [Hash]
|
|
9
|
-
attr_reader :id, :properties
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
# @param id [String]
|
|
13
|
-
# @param properties [Hash]
|
|
14
|
-
#
|
|
15
|
-
def initialize(id:, properties:)
|
|
16
|
-
@id = id
|
|
17
|
-
@properties = properties
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def valid?
|
|
21
|
-
!id.nil? && id.is_a?(String)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module Hackle
|
|
2
|
-
class Variation
|
|
3
|
-
|
|
4
|
-
# @!attribute id
|
|
5
|
-
# @return [Integer]
|
|
6
|
-
# @!attribute key
|
|
7
|
-
# @return [String]
|
|
8
|
-
# @!attribute dropped
|
|
9
|
-
# @return [boolean]
|
|
10
|
-
attr_reader :id, :key, :dropped
|
|
11
|
-
|
|
12
|
-
# @param id [Integer]
|
|
13
|
-
# @param key [String]
|
|
14
|
-
# @param dropped [boolean]
|
|
15
|
-
def initialize(id:, key:, dropped:)
|
|
16
|
-
@id = id
|
|
17
|
-
@key = key
|
|
18
|
-
@dropped = dropped
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'json'
|
|
4
|
-
|
|
5
|
-
module Hackle
|
|
6
|
-
class HttpWorkspaceFetcher
|
|
7
|
-
|
|
8
|
-
def initialize(config:, sdk_info:)
|
|
9
|
-
@client = HTTP.client(base_uri: config.base_uri)
|
|
10
|
-
@headers = HTTP.sdk_headers(sdk_info: sdk_info)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def fetch
|
|
14
|
-
request = Net::HTTP::Get.new('/api/v1/workspaces', @headers)
|
|
15
|
-
response = @client.request(request)
|
|
16
|
-
|
|
17
|
-
status_code = response.code.to_i
|
|
18
|
-
HTTP.check_successful(status_code: status_code)
|
|
19
|
-
|
|
20
|
-
response_body = JSON.parse(response.body, symbolize_names: true)
|
|
21
|
-
Workspace.create(data: response_body)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'concurrent'
|
|
4
|
-
|
|
5
|
-
module Hackle
|
|
6
|
-
class PollingWorkspaceFetcher
|
|
7
|
-
|
|
8
|
-
DEFAULT_POLLING_INTERVAL = 10
|
|
9
|
-
|
|
10
|
-
def initialize(config:, http_fetcher:)
|
|
11
|
-
@logger = config.logger
|
|
12
|
-
@http_fetcher = http_fetcher
|
|
13
|
-
@current_workspace = Concurrent::AtomicReference.new
|
|
14
|
-
@task = Concurrent::TimerTask.new(execution_interval: DEFAULT_POLLING_INTERVAL) { poll }
|
|
15
|
-
@running = false
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# @return [Workspace, nil]
|
|
19
|
-
def fetch
|
|
20
|
-
@current_workspace.get
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def start!
|
|
24
|
-
return if @running
|
|
25
|
-
|
|
26
|
-
poll
|
|
27
|
-
@task.execute
|
|
28
|
-
@running = true
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def stop!
|
|
32
|
-
return unless @running
|
|
33
|
-
|
|
34
|
-
@logger.info { 'Shutting down Hackle workspace_fetcher' }
|
|
35
|
-
|
|
36
|
-
@task.shutdown
|
|
37
|
-
@running = false
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def poll
|
|
41
|
-
workspace = @http_fetcher.fetch
|
|
42
|
-
@current_workspace.set(workspace)
|
|
43
|
-
rescue => e
|
|
44
|
-
@logger.error { "Failed to poll Workspace: #{e.inspect}" }
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
module Hackle
|
|
2
|
-
class Workspace
|
|
3
|
-
|
|
4
|
-
# @param experiments [Hash{Integer => Experiment}]
|
|
5
|
-
# @param event_types [Hash{String => EventType}]
|
|
6
|
-
def initialize(experiments:, event_types:)
|
|
7
|
-
|
|
8
|
-
# @type [Hash{Integer => Experiment}]
|
|
9
|
-
@experiments = experiments
|
|
10
|
-
|
|
11
|
-
# @type [Hash{String => EventType}]
|
|
12
|
-
@event_types = event_types
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
# @param experiment_key [Integer]
|
|
16
|
-
#
|
|
17
|
-
# @return [Experiment, nil]
|
|
18
|
-
def get_experiment(experiment_key:)
|
|
19
|
-
@experiments[experiment_key]
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# @param event_type_key [String]
|
|
23
|
-
#
|
|
24
|
-
# @return [EventType]
|
|
25
|
-
def get_event_type(event_type_key:)
|
|
26
|
-
event_type = @event_types[event_type_key]
|
|
27
|
-
|
|
28
|
-
if event_type.nil?
|
|
29
|
-
EventType.undefined(key: event_type_key)
|
|
30
|
-
else
|
|
31
|
-
event_type
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
class << self
|
|
36
|
-
def create(data:)
|
|
37
|
-
buckets = Hash[data[:buckets].map { |b| [b[:id], bucket(b)] }]
|
|
38
|
-
running_experiments = Hash[data[:experiments].map { |re| [re[:key], running_experiment(re, buckets)] }]
|
|
39
|
-
completed_experiment = Hash[data[:completedExperiments].map { |ce| [ce[:experimentKey], completed_experiment(ce)] }]
|
|
40
|
-
event_types = Hash[data[:events].map { |e| [e[:key], event_type(e)] }]
|
|
41
|
-
experiments = running_experiments.merge(completed_experiment)
|
|
42
|
-
Workspace.new(
|
|
43
|
-
experiments: experiments,
|
|
44
|
-
event_types: event_types
|
|
45
|
-
)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
def running_experiment(data, buckets)
|
|
51
|
-
Experiment::Running.new(
|
|
52
|
-
id: data[:id],
|
|
53
|
-
key: data[:key],
|
|
54
|
-
bucket: buckets[data[:bucketId]],
|
|
55
|
-
variations: Hash[data[:variations].map { |v| [v[:id], variation(v)] }],
|
|
56
|
-
overrides: Hash[data[:execution][:userOverrides].map { |u| [u[:userId], u[:variationId]] }]
|
|
57
|
-
)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def completed_experiment(data)
|
|
61
|
-
Experiment::Completed.new(
|
|
62
|
-
id: data[:experimentId],
|
|
63
|
-
key: data[:experimentKey],
|
|
64
|
-
winner_variation_key: data[:winnerVariationKey]
|
|
65
|
-
)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def variation(data)
|
|
69
|
-
Variation.new(
|
|
70
|
-
id: data[:id],
|
|
71
|
-
key: data[:key],
|
|
72
|
-
dropped: data[:status] == 'DROPPED'
|
|
73
|
-
)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def bucket(data)
|
|
77
|
-
Bucket.new(
|
|
78
|
-
seed: data[:seed],
|
|
79
|
-
slot_size: data[:slotSize],
|
|
80
|
-
slots: data[:slots].map { |s| slot(s) }
|
|
81
|
-
)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def slot(data)
|
|
85
|
-
Slot.new(
|
|
86
|
-
start_inclusive: data[:startInclusive],
|
|
87
|
-
end_exclusive: data[:endExclusive],
|
|
88
|
-
variation_id: data[:variationId]
|
|
89
|
-
)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def event_type(data)
|
|
93
|
-
EventType.new(
|
|
94
|
-
id: data[:id],
|
|
95
|
-
key: data[:key]
|
|
96
|
-
)
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|