unleash 5.1.1 → 6.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44064e0f055213d874e3b4497fb818ed2afc2da440b328a8f34018ce4e961fb2
4
- data.tar.gz: d16679ae82ec9a660e000de12b949763970761be7ad9b87acdc34f774eed55f9
3
+ metadata.gz: 518b79d43627fa6a3de4b59eb7e6f445ebb09a7f8e96f963765ada55c827ac5b
4
+ data.tar.gz: c1c284bee319185697a6eb16d0b10d62c141372b708baa34ad4de682795db1cc
5
5
  SHA512:
6
- metadata.gz: cd655ddf7878c42e48659684d53c88409aa6b05aab1caa63a4ed63a6c10bedbf77c6d62f59a0936e25051a0dd43f8bba92b3a9ab691a265af8ff0f3830c7fd2d
7
- data.tar.gz: 79ca1c3b5c1ff9b77a9751434a5e99a7d29a138839a818b3093684f18c748633fef76f32b75761da1d62693526d1fed6eb4d5e56e434ce60e20050daac1398b8
6
+ metadata.gz: c17939c596ca7523d6d6abec6f36041555fcfbed36bfadcb105a7d6704822a85c3e673f53db23cedcdf560181591b69ec8b8f4bc009a29e6f4cbf39a943b0dda
7
+ data.tar.gz: d61f27c3cf5e726bbcc85401512a3009b9ccfbaa289b12ebf930af30fe6606c340eed26b57aba84425cafcc792120bcf003e36512d56168ca7d2cac75eff9d90
data/CHANGELOG.md CHANGED
@@ -13,6 +13,12 @@ Note: These changes are not considered notable:
13
13
 
14
14
  ## [Unreleased]
15
15
 
16
+ ## [6.0.0.pre] - 2024-09-25
17
+ #### Changed
18
+ - No longer possible to override built in strategies with custom strategies (#152)
19
+ - No longer possible to access built in strategy's objects, these are now native code (#152)
20
+ - Core of the SDK swapped for Yggdrasil engine (#152)
21
+
16
22
  ## [5.1.1] - 2024-09-23
17
23
  ### Fixed
18
24
  - increased accuracy of rollout distribution (#200)
@@ -2,7 +2,7 @@ require 'unleash/configuration'
2
2
  require 'unleash/toggle_fetcher'
3
3
  require 'unleash/metrics_reporter'
4
4
  require 'unleash/scheduled_executor'
5
- require 'unleash/feature_toggle'
5
+ require 'unleash/variant'
6
6
  require 'unleash/util/http'
7
7
  require 'logger'
8
8
  require 'time'
@@ -11,14 +11,17 @@ module Unleash
11
11
  class Client
12
12
  attr_accessor :fetcher_scheduled_executor, :metrics_scheduled_executor
13
13
 
14
+ # rubocop:disable Metrics/AbcSize
14
15
  def initialize(*opts)
15
16
  Unleash.configuration = Unleash::Configuration.new(*opts) unless opts.empty?
16
17
  Unleash.configuration.validate!
17
18
 
18
19
  Unleash.logger = Unleash.configuration.logger.clone
19
20
  Unleash.logger.level = Unleash.configuration.log_level
21
+ Unleash.engine = YggdrasilEngine.new
22
+ Unleash.engine.register_custom_strategies(Unleash.configuration.strategies.custom_strategies)
20
23
 
21
- Unleash.toggle_fetcher = Unleash::ToggleFetcher.new
24
+ Unleash.toggle_fetcher = Unleash::ToggleFetcher.new Unleash.engine
22
25
  if Unleash.configuration.disable_client
23
26
  Unleash.logger.warn "Unleash::Client is disabled! Will only return default (or bootstrapped if available) results!"
24
27
  Unleash.logger.warn "Unleash::Client is disabled! Metrics and MetricsReporter are also disabled!"
@@ -30,6 +33,7 @@ module Unleash
30
33
  start_toggle_fetcher
31
34
  start_metrics unless Unleash.configuration.disable_metrics
32
35
  end
36
+ # rubocop:enable Metrics/AbcSize
33
37
 
34
38
  def is_enabled?(feature, context = nil, default_value_param = false, &fallback_blk)
35
39
  Unleash.logger.debug "Unleash::Client.is_enabled? feature: #{feature} with context #{context}"
@@ -40,15 +44,16 @@ module Unleash
40
44
  default_value_param
41
45
  end
42
46
 
43
- toggle_as_hash = Unleash&.toggles&.select{ |toggle| toggle['name'] == feature }&.first
44
- if toggle_as_hash.nil?
47
+ toggle_enabled = Unleash.engine.enabled?(feature, context)
48
+ if toggle_enabled.nil?
45
49
  Unleash.logger.debug "Unleash::Client.is_enabled? feature: #{feature} not found"
50
+ Unleash.engine.count_toggle(feature, false)
46
51
  return default_value
47
52
  end
48
53
 
49
- toggle = Unleash::FeatureToggle.new(toggle_as_hash, Unleash&.segment_cache)
54
+ Unleash.engine.count_toggle(feature, toggle_enabled)
50
55
 
51
- toggle.is_enabled?(context)
56
+ toggle_enabled
52
57
  end
53
58
 
54
59
  def is_disabled?(feature, context = nil, default_value_param = true, &fallback_blk)
@@ -71,23 +76,19 @@ module Unleash
71
76
  end
72
77
 
73
78
  def get_variant(feature, context = Unleash::Context.new, fallback_variant = disabled_variant)
74
- Unleash.logger.debug "Unleash::Client.get_variant for feature: #{feature} with context #{context}"
75
-
76
- toggle_as_hash = Unleash&.toggles&.select{ |toggle| toggle['name'] == feature }&.first
77
-
78
- if toggle_as_hash.nil?
79
- Unleash.logger.debug "Unleash::Client.get_variant feature: #{feature} not found"
80
- return fallback_variant
81
- end
82
-
83
- toggle = Unleash::FeatureToggle.new(toggle_as_hash, Unleash&.segment_cache)
84
- variant = toggle.get_variant(context, fallback_variant)
79
+ variant = Unleash.engine.get_variant(feature, context)
85
80
 
86
81
  if variant.nil?
87
82
  Unleash.logger.debug "Unleash::Client.get_variant variants for feature: #{feature} not found"
83
+ Unleash.engine.count_toggle(feature, false)
88
84
  return fallback_variant
89
85
  end
90
86
 
87
+ variant = Variant.new(variant)
88
+
89
+ Unleash.engine.count_variant(feature, variant.name)
90
+ Unleash.engine.count_toggle(feature, variant.feature_enabled)
91
+
91
92
  # TODO: Add to README: name, payload, enabled (bool)
92
93
 
93
94
  variant
@@ -96,7 +97,6 @@ module Unleash
96
97
  # safe shutdown: also flush metrics to server and toggles to disk
97
98
  def shutdown
98
99
  unless Unleash.configuration.disable_client
99
- Unleash.toggle_fetcher.save!
100
100
  Unleash.reporter.post unless Unleash.configuration.disable_metrics
101
101
  shutdown!
102
102
  end
@@ -117,12 +117,12 @@ module Unleash
117
117
  'appName': Unleash.configuration.app_name,
118
118
  'instanceId': Unleash.configuration.instance_id,
119
119
  'sdkVersion': "unleash-client-ruby:" + Unleash::VERSION,
120
- 'strategies': Unleash.strategies.keys,
120
+ 'strategies': Unleash.strategies.known_strategies,
121
121
  'started': Time.now.iso8601(Unleash::TIME_RESOLUTION),
122
122
  'interval': Unleash.configuration.metrics_interval_in_millis,
123
123
  'platformName': RUBY_ENGINE,
124
124
  'platformVersion': RUBY_VERSION,
125
- 'yggdrasilVersion': nil,
125
+ 'yggdrasilVersion': "0.13.2",
126
126
  'specVersion': Unleash::CLIENT_SPECIFICATION_VERSION
127
127
  }
128
128
  end
@@ -140,7 +140,6 @@ module Unleash
140
140
  end
141
141
 
142
142
  def start_metrics
143
- Unleash.toggle_metrics = Unleash::Metrics.new
144
143
  Unleash.reporter = Unleash::MetricsReporter.new
145
144
  self.metrics_scheduled_executor = Unleash::ScheduledExecutor.new(
146
145
  'MetricsReporter',
@@ -166,7 +165,7 @@ module Unleash
166
165
  end
167
166
 
168
167
  def disabled_variant
169
- @disabled_variant ||= Unleash::FeatureToggle.disabled_variant
168
+ @disabled_variant ||= Unleash::Variant.disabled_variant
170
169
  end
171
170
 
172
171
  def first_fetch_is_eager
@@ -40,9 +40,9 @@ module Unleash
40
40
  def validate!
41
41
  return if self.disable_client
42
42
 
43
- raise ArgumentError, "URL and app_name are required parameters." if self.app_name.nil? || self.url.nil?
43
+ raise ArgumentError, "app_name is a required parameter." if self.app_name.nil?
44
44
 
45
- validate_custom_http_headers!(self.custom_http_headers)
45
+ validate_custom_http_headers!(self.custom_http_headers) unless self.url.nil?
46
46
  end
47
47
 
48
48
  def refresh_backup_file!
@@ -7,20 +7,36 @@ module Unleash
7
7
  def initialize(params = {})
8
8
  raise ArgumentError, "Unleash::Context must be initialized with a hash." unless params.is_a?(Hash)
9
9
 
10
- self.app_name = value_for('appName', params, Unleash&.configuration&.app_name)
11
- self.environment = value_for('environment', params, Unleash&.configuration&.environment || 'default')
12
- self.user_id = value_for('userId', params)&.to_s
13
- self.session_id = value_for('sessionId', params)
14
- self.remote_address = value_for('remoteAddress', params)
15
- self.current_time = value_for('currentTime', params, Time.now.utc.iso8601.to_s)
16
-
17
- properties = value_for('properties', params)
10
+ self.app_name = value_for("appName", params, Unleash&.configuration&.app_name)
11
+ self.environment = value_for("environment", params, Unleash&.configuration&.environment || "default")
12
+ self.user_id = value_for("userId", params)&.to_s
13
+ self.session_id = value_for("sessionId", params)
14
+ self.remote_address = value_for("remoteAddress", params)
15
+ self.current_time = value_for("currentTime", params, Time.now.utc.iso8601.to_s)
16
+
17
+ properties = value_for("properties", params)
18
18
  self.properties = properties.is_a?(Hash) ? properties.transform_keys(&:to_sym) : {}
19
19
  end
20
20
 
21
21
  def to_s
22
22
  "<Context: user_id=#{@user_id},session_id=#{@session_id},remote_address=#{@remote_address},properties=#{@properties}" \
23
- ",app_name=#{@app_name},environment=#{@environment},current_time=#{@current_time}>"
23
+ ",app_name=#{@app_name},environment=#{@environment},current_time=#{@current_time}>"
24
+ end
25
+
26
+ def as_json
27
+ {
28
+ appName: to_safe_value(self.app_name),
29
+ environment: to_safe_value(self.environment),
30
+ userId: to_safe_value(self.user_id),
31
+ sessionId: to_safe_value(self.session_id),
32
+ remoteAddress: to_safe_value(self.remote_address),
33
+ currentTime: to_safe_value(self.current_time),
34
+ properties: self.properties.transform_values{ |value| to_safe_value(value) }
35
+ }
36
+ end
37
+
38
+ def to_json(*options)
39
+ as_json(*options).to_json(*options)
24
40
  end
25
41
 
26
42
  def to_h
@@ -52,6 +68,16 @@ module Unleash
52
68
  params.values_at(key, key.to_sym, underscore(key), underscore(key).to_sym).compact.first || default_value
53
69
  end
54
70
 
71
+ def to_safe_value(value)
72
+ return nil if value.nil?
73
+
74
+ if value.is_a?(Time)
75
+ value.utc.iso8601
76
+ else
77
+ value.to_s
78
+ end
79
+ end
80
+
55
81
  # converts CamelCase to snake_case
56
82
  def underscore(camel_cased_word)
57
83
  camel_cased_word.to_s.gsub(/(.)([A-Z])/, '\1_\2').downcase
@@ -1,5 +1,4 @@
1
1
  require 'unleash/configuration'
2
- require 'unleash/metrics'
3
2
  require 'net/http'
4
3
  require 'json'
5
4
  require 'time'
@@ -15,52 +14,39 @@ module Unleash
15
14
  end
16
15
 
17
16
  def generate_report
18
- now = Time.now
17
+ metrics = Unleash&.engine&.get_metrics()
18
+ return nil if metrics.nil? || metrics.empty?
19
19
 
20
- start = self.last_time
21
- stop = now
22
- self.last_time = now
23
-
24
- report = {
25
- 'appName': Unleash.configuration.app_name,
26
- 'instanceId': Unleash.configuration.instance_id,
20
+ {
27
21
  'platformName': RUBY_ENGINE,
28
22
  'platformVersion': RUBY_VERSION,
29
- 'yggdrasilVersion': nil,
23
+ 'yggdrasilVersion': "0.13.2",
30
24
  'specVersion': Unleash::CLIENT_SPECIFICATION_VERSION,
31
- 'bucket': {
32
- 'start': start.iso8601(Unleash::TIME_RESOLUTION),
33
- 'stop': stop.iso8601(Unleash::TIME_RESOLUTION),
34
- 'toggles': Unleash.toggle_metrics.features
35
- }
25
+ 'appName': Unleash.configuration.app_name,
26
+ 'instanceId': Unleash.configuration.instance_id,
27
+ 'bucket': metrics
36
28
  }
37
- Unleash.toggle_metrics.reset
38
-
39
- report
40
29
  end
41
30
 
42
31
  def post
43
32
  Unleash.logger.debug "post() Report"
44
33
 
45
- if bucket_empty? && (Time.now - self.last_time < LONGEST_WITHOUT_A_REPORT) # and last time is less then 10 minutes...
34
+ bucket = self.generate_report
35
+ if bucket.nil? && (Time.now - self.last_time < LONGEST_WITHOUT_A_REPORT) # and last time is less then 10 minutes...
46
36
  Unleash.logger.debug "Report not posted to server, as it would have been empty. (and has been empty for up to 10 min)"
47
37
 
48
38
  return
49
39
  end
50
40
 
51
- response = Unleash::Util::Http.post(Unleash.configuration.client_metrics_uri, self.generate_report.to_json)
41
+ response = Unleash::Util::Http.post(Unleash.configuration.client_metrics_uri, bucket.to_json)
52
42
 
53
43
  if ['200', '202'].include? response.code
54
44
  Unleash.logger.debug "Report sent to unleash server successfully. Server responded with http code #{response.code}"
55
45
  else
46
+ # :nocov:
56
47
  Unleash.logger.error "Error when sending report to unleash server. Server responded with http code #{response.code}."
48
+ # :nocov:
57
49
  end
58
50
  end
59
-
60
- private
61
-
62
- def bucket_empty?
63
- Unleash.toggle_metrics.features.empty?
64
- end
65
51
  end
66
52
  end
@@ -1,92 +1,33 @@
1
- require 'unleash/strategy/base'
2
- Gem.find_files('unleash/strategy/**/*.rb').each{ |path| require path }
3
-
4
1
  module Unleash
2
+ class DefaultOverrideError < RuntimeError
3
+ end
4
+
5
5
  class Strategies
6
+ attr_accessor :strategies
7
+
6
8
  def initialize
7
9
  @strategies = {}
8
- register_strategies
9
- end
10
-
11
- def keys
12
- @strategies.keys
13
10
  end
14
11
 
15
12
  def includes?(name)
16
- @strategies.has_key?(name.to_s)
17
- end
18
-
19
- def fetch(name)
20
- raise Unleash::Strategy::NotImplemented, "Strategy is not implemented" unless (strategy = @strategies[name.to_s])
21
-
22
- strategy
13
+ @strategies.has_key?(name.to_s) || DEFAULT_STRATEGIES.include?(name.to_s)
23
14
  end
24
15
 
25
16
  def add(strategy)
26
- if default_strategy_names.include?(strategy.name)
27
- Unleash.logger.error "WARNING: Overriding built in strategy '#{strategy.name}'. OVERIDING BUILT IN STRATEGIES IS \
28
- DEPRECATED AND WILL BE REMOVED IN A FUTURE RELEASE."
29
- end
30
- self.internal_add(strategy)
31
- end
32
-
33
- def []=(key, strategy)
34
- warn_deprecated_registration(strategy, 'modifying Unleash::STRATEGIES')
35
- @strategies[key.to_s] = strategy
36
- end
17
+ raise DefaultOverrideError, "Cannot override a default strategy" if DEFAULT_STRATEGIES.include?(strategy.name)
37
18
 
38
- def [](key)
39
- @strategies[key.to_s]
40
- end
41
-
42
- def register_strategies
43
- register_base_strategies
44
- register_custom_strategies
45
- end
46
-
47
- protected
48
-
49
- # Deprecated: Use Unleash.configuration to add custom strategies
50
- def register_custom_strategies
51
- Unleash::Strategy.constants
52
- .select{ |c| Unleash::Strategy.const_get(c).is_a? Class }
53
- .reject{ |c| ['NotImplemented', 'Base'].include?(c.to_s) } # Reject abstract classes
54
- .map{ |c| Object.const_get("Unleash::Strategy::#{c}") }
55
- .reject{ |c| DEFAULT_STRATEGIES.include?(c) } # Reject base classes
56
- .each do |c|
57
- strategy = c.new
58
- warn_deprecated_registration(strategy, 'adding custom class into Unleash::Strategy namespace')
59
- self.internal_add(strategy)
60
- end
61
- end
62
-
63
- def register_base_strategies
64
- DEFAULT_STRATEGIES.each{ |c| self.internal_add(c.new) }
65
- end
66
-
67
- def internal_add(strategy)
68
19
  @strategies[strategy.name] = strategy
69
20
  end
70
21
 
71
- def default_strategy_names
72
- DEFAULT_STRATEGIES.map{ |strategy_class| strategy_class.new.name }
22
+ def custom_strategies
23
+ @strategies.values
73
24
  end
74
25
 
75
- DEFAULT_STRATEGIES = [
76
- Unleash::Strategy::ApplicationHostname,
77
- Unleash::Strategy::Default,
78
- Unleash::Strategy::FlexibleRollout,
79
- Unleash::Strategy::GradualRolloutRandom,
80
- Unleash::Strategy::GradualRolloutSessionId,
81
- Unleash::Strategy::GradualRolloutUserId,
82
- Unleash::Strategy::RemoteAddress,
83
- Unleash::Strategy::UserWithId
84
- ].freeze
85
-
86
- def warn_deprecated_registration(strategy, method)
87
- warn "[DEPRECATED] Registering custom Unleash strategy by #{method} is deprecated.
88
- Please use Unleash configuration to register custom strategy: " \
89
- "`Unleash.configure {|c| c.strategies.add(#{strategy.class.name}.new) }`"
26
+ def known_strategies
27
+ @strategies.keys.map{ |key| { name: key } }
90
28
  end
29
+
30
+ DEFAULT_STRATEGIES = ['applicationHostname', 'default', 'flexibleRollout', 'gradualRolloutRandom', 'gradualRolloutSessionId',
31
+ 'gradualRolloutUserId', 'remoteAddress', 'userWithId'].freeze
91
32
  end
92
33
  end
@@ -2,15 +2,15 @@ require 'unleash/configuration'
2
2
  require 'unleash/bootstrap/handler'
3
3
  require 'net/http'
4
4
  require 'json'
5
+ require 'yggdrasil_engine'
5
6
 
6
7
  module Unleash
7
8
  class ToggleFetcher
8
- attr_accessor :toggle_cache, :toggle_lock, :toggle_resource, :etag, :retry_count, :segment_cache
9
+ attr_accessor :toggle_engine, :toggle_lock, :toggle_resource, :etag, :retry_count
9
10
 
10
- def initialize
11
+ def initialize(engine)
12
+ self.toggle_engine = engine
11
13
  self.etag = nil
12
- self.toggle_cache = nil
13
- self.segment_cache = nil
14
14
  self.toggle_lock = Mutex.new
15
15
  self.toggle_resource = ConditionVariable.new
16
16
  self.retry_count = 0
@@ -32,14 +32,6 @@ module Unleash
32
32
  # once initialized, somewhere else you will want to start a loop with fetch()
33
33
  end
34
34
 
35
- def toggles
36
- self.toggle_lock.synchronize do
37
- # wait for resource, only if it is null
38
- self.toggle_resource.wait(self.toggle_lock) if self.toggle_cache.nil?
39
- return self.toggle_cache
40
- end
41
- end
42
-
43
35
  # rename to refresh_from_server! ??
44
36
  def fetch
45
37
  Unleash.logger.debug "fetch()"
@@ -55,16 +47,14 @@ module Unleash
55
47
  end
56
48
 
57
49
  self.etag = response['ETag']
58
- features = get_features(response.body)
59
50
 
60
51
  # always synchronize with the local cache when fetching:
61
- synchronize_with_local_cache!(features)
52
+ update_engine_state!(response.body)
62
53
 
63
- update_running_client!
64
- save!
54
+ save! response.body
65
55
  end
66
56
 
67
- def save!
57
+ def save!(toggle_data)
68
58
  Unleash.logger.debug "Will save toggles to disk now"
69
59
 
70
60
  backup_file = Unleash.configuration.backup_file
@@ -72,7 +62,7 @@ module Unleash
72
62
 
73
63
  self.toggle_lock.synchronize do
74
64
  File.open(backup_file_tmp, "w") do |file|
75
- file.write(self.toggle_cache.to_json)
65
+ file.write(toggle_data)
76
66
  end
77
67
  File.rename(backup_file_tmp, backup_file)
78
68
  end
@@ -84,23 +74,13 @@ module Unleash
84
74
 
85
75
  private
86
76
 
87
- def synchronize_with_local_cache!(features)
88
- if self.toggle_cache != features
89
- self.toggle_lock.synchronize do
90
- self.toggle_cache = features
91
- end
92
-
93
- # notify all threads waiting for this resource to no longer wait
94
- self.toggle_resource.broadcast
77
+ def update_engine_state!(toggle_data)
78
+ self.toggle_lock.synchronize do
79
+ self.toggle_engine.take_state(toggle_data)
95
80
  end
96
- end
97
81
 
98
- def update_running_client!
99
- if Unleash.toggles != self.toggles["features"] || Unleash.segment_cache != self.toggles["segments"]
100
- Unleash.logger.info "Updating toggles to main client, there has been a change in the server."
101
- Unleash.toggles = self.toggles["features"]
102
- Unleash.segment_cache = self.toggles["segments"]
103
- end
82
+ # notify all threads waiting for this resource to no longer wait
83
+ self.toggle_resource.broadcast
104
84
  end
105
85
 
106
86
  def read!
@@ -108,42 +88,28 @@ module Unleash
108
88
  backup_file = Unleash.configuration.backup_file
109
89
  return nil unless File.exist?(backup_file)
110
90
 
111
- backup_as_hash = JSON.parse(File.read(backup_file))
112
- synchronize_with_local_cache!(backup_as_hash)
113
- update_running_client!
91
+ backup_data = File.read(backup_file)
92
+ update_engine_state!(backup_data)
114
93
  rescue IOError => e
94
+ # :nocov:
115
95
  Unleash.logger.error "Unable to read the backup_file: #{e}"
96
+ # :nocov:
116
97
  rescue JSON::ParserError => e
98
+ # :nocov:
117
99
  Unleash.logger.error "Unable to parse JSON from existing backup_file: #{e}"
100
+ # :nocov:
118
101
  rescue StandardError => e
102
+ # :nocov:
119
103
  Unleash.logger.error "Unable to extract valid data from backup_file. Exception thrown: #{e}"
104
+ # :nocov:
120
105
  end
121
106
 
122
107
  def bootstrap
123
108
  bootstrap_payload = Unleash::Bootstrap::Handler.new(Unleash.configuration.bootstrap_config).retrieve_toggles
124
- synchronize_with_local_cache! get_features bootstrap_payload
125
- update_running_client!
109
+ update_engine_state! bootstrap_payload
126
110
 
127
111
  # reset Unleash.configuration.bootstrap_data to free up memory, as we will never use it again
128
112
  Unleash.configuration.bootstrap_config = nil
129
113
  end
130
-
131
- def build_segment_map(segments_array)
132
- return {} if segments_array.nil?
133
-
134
- segments_array.map{ |segment| [segment["id"], segment] }.to_h
135
- end
136
-
137
- # @param response_body [String]
138
- def get_features(response_body)
139
- response_hash = JSON.parse(response_body)
140
-
141
- if response_hash['version'] >= 1
142
- return { "features" => response_hash["features"], "segments" => build_segment_map(response_hash["segments"]) }
143
- end
144
-
145
- raise NotImplemented, "Version of features provided by unleash server" \
146
- " is unsupported by this client."
147
- end
148
114
  end
149
115
  end
@@ -14,12 +14,18 @@ module Unleash
14
14
  end
15
15
 
16
16
  def to_s
17
+ # :nocov:
17
18
  "<Variant: name=#{self.name},enabled=#{self.enabled},payload=#{self.payload},feature_enabled=#{self.feature_enabled}>"
19
+ # :nocov:
18
20
  end
19
21
 
20
22
  def ==(other)
21
23
  self.name == other.name && self.enabled == other.enabled && self.payload == other.payload \
22
24
  && self.feature_enabled == other.feature_enabled
23
25
  end
26
+
27
+ def self.disabled_variant
28
+ Variant.new(name: 'disabled', enabled: false, feature_enabled: false)
29
+ end
24
30
  end
25
31
  end
@@ -1,3 +1,3 @@
1
1
  module Unleash
2
- VERSION = "5.1.1".freeze
2
+ VERSION = "6.0.0.pre".freeze
3
3
  end
data/lib/unleash.rb CHANGED
@@ -10,7 +10,7 @@ module Unleash
10
10
  TIME_RESOLUTION = 3
11
11
 
12
12
  class << self
13
- attr_accessor :configuration, :toggle_fetcher, :toggles, :toggle_metrics, :reporter, :segment_cache, :logger
13
+ attr_accessor :configuration, :toggle_fetcher, :reporter, :logger, :engine
14
14
  end
15
15
 
16
16
  self.configuration = Unleash::Configuration.new
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.required_ruby_version = ">= 2.6"
25
25
 
26
26
  spec.add_dependency "murmurhash3", "~> 0.1.7"
27
+ spec.add_dependency "yggdrasil-engine", "~> 0.0.5"
27
28
 
28
29
  spec.add_development_dependency "bundler", "~> 2.1"
29
30
  spec.add_development_dependency "rake", "~> 12.3"