unleash 4.4.4 → 6.4.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/.github/workflows/pull_request.yml +15 -15
- data/.rubocop.yml +5 -1
- data/CHANGELOG.md +147 -1
- data/README.md +161 -144
- data/bin/unleash-client +1 -1
- data/echo_client_spec_version.rb +3 -0
- data/examples/extending_unleash_with_opentelemetry.rb +63 -0
- data/examples/simple.rb +3 -4
- data/examples/streaming.rb +50 -0
- data/lib/unleash/bootstrap/handler.rb +2 -1
- data/lib/unleash/client.rb +47 -26
- data/lib/unleash/configuration.rb +48 -7
- data/lib/unleash/context.rb +35 -9
- data/lib/unleash/metrics_reporter.rb +39 -28
- data/lib/unleash/spec_version.rb +3 -0
- data/lib/unleash/strategies.rb +14 -61
- data/lib/unleash/streaming_client_executor.rb +85 -0
- data/lib/unleash/streaming_event_processor.rb +53 -0
- data/lib/unleash/toggle_fetcher.rb +29 -58
- data/lib/unleash/util/event_source_wrapper.rb +17 -0
- data/lib/unleash/util/http.rb +3 -2
- data/lib/unleash/variant.rb +11 -3
- data/lib/unleash/version.rb +1 -1
- data/lib/unleash.rb +2 -1
- data/unleash-client.gemspec +8 -4
- data/v6_MIGRATION_GUIDE.md +21 -0
- metadata +60 -26
- data/lib/unleash/activation_strategy.rb +0 -31
- data/lib/unleash/constraint.rb +0 -115
- data/lib/unleash/feature_toggle.rb +0 -187
- data/lib/unleash/metrics.rb +0 -41
- data/lib/unleash/strategy/application_hostname.rb +0 -26
- data/lib/unleash/strategy/base.rb +0 -16
- data/lib/unleash/strategy/default.rb +0 -13
- data/lib/unleash/strategy/flexible_rollout.rb +0 -64
- data/lib/unleash/strategy/gradual_rollout_random.rb +0 -24
- data/lib/unleash/strategy/gradual_rollout_sessionid.rb +0 -21
- data/lib/unleash/strategy/gradual_rollout_userid.rb +0 -21
- data/lib/unleash/strategy/remote_address.rb +0 -36
- data/lib/unleash/strategy/user_with_id.rb +0 -20
- data/lib/unleash/strategy/util.rb +0 -16
- data/lib/unleash/variant_definition.rb +0 -26
- data/lib/unleash/variant_override.rb +0 -44
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'unleash/streaming_event_processor'
|
2
|
+
require 'unleash/util/event_source_wrapper'
|
3
|
+
|
4
|
+
module Unleash
|
5
|
+
class StreamingClientExecutor
|
6
|
+
attr_accessor :name, :event_source, :event_processor, :running
|
7
|
+
|
8
|
+
def initialize(name, engine)
|
9
|
+
self.name = name || 'StreamingClientExecutor'
|
10
|
+
self.event_source = nil
|
11
|
+
self.event_processor = Unleash::StreamingEventProcessor.new(engine)
|
12
|
+
self.running = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(&_block)
|
16
|
+
start
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
return if self.running || Unleash.configuration.disable_client
|
21
|
+
|
22
|
+
Unleash.logger.debug "Streaming client #{self.name} starting connection to: #{Unleash.configuration.fetch_toggles_uri}"
|
23
|
+
|
24
|
+
self.event_source = create_event_source
|
25
|
+
setup_event_handlers
|
26
|
+
|
27
|
+
self.running = true
|
28
|
+
Unleash.logger.debug "Streaming client #{self.name} connection established"
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop
|
32
|
+
return unless self.running
|
33
|
+
|
34
|
+
Unleash.logger.debug "Streaming client #{self.name} stopping connection"
|
35
|
+
self.running = false
|
36
|
+
self.event_source&.close
|
37
|
+
self.event_source = nil
|
38
|
+
Unleash.logger.debug "Streaming client #{self.name} connection closed"
|
39
|
+
end
|
40
|
+
|
41
|
+
alias exit stop
|
42
|
+
|
43
|
+
def running?
|
44
|
+
self.running
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def create_event_source
|
50
|
+
sse_client = Unleash::Util::EventSourceWrapper.client
|
51
|
+
if sse_client.nil?
|
52
|
+
raise "Streaming mode is configured but EventSource client is not available. " \
|
53
|
+
"Please install the 'ld-eventsource' gem or switch to polling mode."
|
54
|
+
end
|
55
|
+
|
56
|
+
headers = (Unleash.configuration.http_headers || {}).dup
|
57
|
+
|
58
|
+
sse_client.new(
|
59
|
+
Unleash.configuration.fetch_toggles_uri.to_s,
|
60
|
+
headers: headers,
|
61
|
+
read_timeout: 60,
|
62
|
+
reconnect_time: 2,
|
63
|
+
connect_timeout: 10,
|
64
|
+
logger: Unleash.logger
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup_event_handlers
|
69
|
+
self.event_source.on_event do |event|
|
70
|
+
handle_event(event)
|
71
|
+
end
|
72
|
+
|
73
|
+
self.event_source.on_error do |error|
|
74
|
+
Unleash.logger.warn "Streaming client #{self.name} error: #{error}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_event(event)
|
79
|
+
self.event_processor.process_event(event)
|
80
|
+
rescue StandardError => e
|
81
|
+
Unleash.logger.error "Streaming client #{self.name} threw exception #{e.class}: '#{e}'"
|
82
|
+
Unleash.logger.debug "stacktrace: #{e.backtrace}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Unleash
|
4
|
+
class StreamingEventProcessor
|
5
|
+
attr_accessor :toggle_engine, :mutex
|
6
|
+
|
7
|
+
def initialize(toggle_engine)
|
8
|
+
self.toggle_engine = toggle_engine
|
9
|
+
self.mutex = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def process_event(event)
|
13
|
+
case event.type.to_s
|
14
|
+
when 'unleash-connected'
|
15
|
+
Unleash.logger.debug "Streaming client connected"
|
16
|
+
handle_connected_event(event)
|
17
|
+
when 'unleash-updated'
|
18
|
+
Unleash.logger.debug "Received streaming update"
|
19
|
+
handle_updated_event(event)
|
20
|
+
else
|
21
|
+
Unleash.logger.debug "Received unknown event type: #{event.type}"
|
22
|
+
end
|
23
|
+
rescue StandardError => e
|
24
|
+
Unleash.logger.error "Error handling streaming event threw exception #{e.class}: '#{e}'"
|
25
|
+
Unleash.logger.debug "stacktrace: #{e.backtrace}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_delta_event(event_data)
|
29
|
+
self.mutex.synchronize do
|
30
|
+
self.toggle_engine.take_state(event_data)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def handle_connected_event(event)
|
37
|
+
Unleash.logger.debug "Processing initial hydration data"
|
38
|
+
handle_updated_event(event)
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_updated_event(event)
|
42
|
+
handle_delta_event(event.data)
|
43
|
+
|
44
|
+
# TODO: update backup file
|
45
|
+
rescue JSON::ParserError => e
|
46
|
+
Unleash.logger.error "Unable to parse JSON from streaming event data. Exception thrown #{e.class}: '#{e}'"
|
47
|
+
Unleash.logger.debug "stacktrace: #{e.backtrace}"
|
48
|
+
rescue StandardError => e
|
49
|
+
Unleash.logger.error "Error processing delta update threw exception #{e.class}: '#{e}'"
|
50
|
+
Unleash.logger.debug "stacktrace: #{e.backtrace}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
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 :
|
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,39 +32,32 @@ 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()"
|
46
38
|
return if Unleash.configuration.disable_client
|
47
39
|
|
48
|
-
|
40
|
+
headers = (Unleash.configuration.http_headers || {}).dup
|
41
|
+
headers.merge!({ 'UNLEASH-INTERVAL' => Unleash.configuration.refresh_interval.to_s })
|
42
|
+
response = Unleash::Util::Http.get(Unleash.configuration.fetch_toggles_uri, etag, headers)
|
49
43
|
|
50
44
|
if response.code == '304'
|
51
45
|
Unleash.logger.debug "No changes according to the unleash server, nothing to do."
|
52
46
|
return
|
53
47
|
elsif response.code != '200'
|
54
|
-
raise IOError, "Unleash server returned
|
48
|
+
raise IOError, "Unleash server returned unexpected HTTP response code #{response.code}."\
|
49
|
+
" Only handle response codes 200 (indicates changes) or 304 (no changes)."
|
55
50
|
end
|
56
51
|
|
57
52
|
self.etag = response['ETag']
|
58
|
-
features = get_features(response.body)
|
59
53
|
|
60
54
|
# always synchronize with the local cache when fetching:
|
61
|
-
|
55
|
+
update_engine_state!(response.body)
|
62
56
|
|
63
|
-
|
64
|
-
save!
|
57
|
+
save! response.body
|
65
58
|
end
|
66
59
|
|
67
|
-
def save!
|
60
|
+
def save!(toggle_data)
|
68
61
|
Unleash.logger.debug "Will save toggles to disk now"
|
69
62
|
|
70
63
|
backup_file = Unleash.configuration.backup_file
|
@@ -72,7 +65,7 @@ module Unleash
|
|
72
65
|
|
73
66
|
self.toggle_lock.synchronize do
|
74
67
|
File.open(backup_file_tmp, "w") do |file|
|
75
|
-
file.write(
|
68
|
+
file.write(toggle_data)
|
76
69
|
end
|
77
70
|
File.rename(backup_file_tmp, backup_file)
|
78
71
|
end
|
@@ -84,23 +77,15 @@ module Unleash
|
|
84
77
|
|
85
78
|
private
|
86
79
|
|
87
|
-
def
|
88
|
-
|
89
|
-
self.
|
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
|
80
|
+
def update_engine_state!(toggle_data)
|
81
|
+
self.toggle_lock.synchronize do
|
82
|
+
self.toggle_engine.take_state(toggle_data)
|
95
83
|
end
|
96
|
-
end
|
97
84
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
Unleash.segment_cache = self.toggles["segments"]
|
103
|
-
end
|
85
|
+
# notify all threads waiting for this resource to no longer wait
|
86
|
+
self.toggle_resource.broadcast
|
87
|
+
rescue StandardError => e
|
88
|
+
Unleash.logger.error "Failed to hydrate state: #{e.backtrace}"
|
104
89
|
end
|
105
90
|
|
106
91
|
def read!
|
@@ -108,42 +93,28 @@ module Unleash
|
|
108
93
|
backup_file = Unleash.configuration.backup_file
|
109
94
|
return nil unless File.exist?(backup_file)
|
110
95
|
|
111
|
-
|
112
|
-
|
113
|
-
update_running_client!
|
96
|
+
backup_data = File.read(backup_file)
|
97
|
+
update_engine_state!(backup_data)
|
114
98
|
rescue IOError => e
|
99
|
+
# :nocov:
|
115
100
|
Unleash.logger.error "Unable to read the backup_file: #{e}"
|
101
|
+
# :nocov:
|
116
102
|
rescue JSON::ParserError => e
|
103
|
+
# :nocov:
|
117
104
|
Unleash.logger.error "Unable to parse JSON from existing backup_file: #{e}"
|
105
|
+
# :nocov:
|
118
106
|
rescue StandardError => e
|
107
|
+
# :nocov:
|
119
108
|
Unleash.logger.error "Unable to extract valid data from backup_file. Exception thrown: #{e}"
|
109
|
+
# :nocov:
|
120
110
|
end
|
121
111
|
|
122
112
|
def bootstrap
|
123
113
|
bootstrap_payload = Unleash::Bootstrap::Handler.new(Unleash.configuration.bootstrap_config).retrieve_toggles
|
124
|
-
|
125
|
-
update_running_client!
|
114
|
+
update_engine_state! bootstrap_payload
|
126
115
|
|
127
116
|
# reset Unleash.configuration.bootstrap_data to free up memory, as we will never use it again
|
128
117
|
Unleash.configuration.bootstrap_config = nil
|
129
118
|
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
119
|
end
|
149
120
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Unleash
|
2
|
+
module Util
|
3
|
+
module EventSourceWrapper
|
4
|
+
def self.client
|
5
|
+
return nil if RUBY_ENGINE == 'jruby'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'ld-eventsource'
|
9
|
+
SSE::Client
|
10
|
+
rescue LoadError => e
|
11
|
+
Unleash.logger.error "Failed to load ld-eventsource: #{e.message}"
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/unleash/util/http.rb
CHANGED
@@ -12,10 +12,10 @@ module Unleash
|
|
12
12
|
http.request(request)
|
13
13
|
end
|
14
14
|
|
15
|
-
def self.post(uri, body)
|
15
|
+
def self.post(uri, body, headers_override = nil)
|
16
16
|
http = http_connection(uri)
|
17
17
|
|
18
|
-
request = Net::HTTP::Post.new(uri.request_uri, http_headers)
|
18
|
+
request = Net::HTTP::Post.new(uri.request_uri, http_headers(nil, headers_override))
|
19
19
|
request.body = body
|
20
20
|
|
21
21
|
http.request(request)
|
@@ -24,6 +24,7 @@ module Unleash
|
|
24
24
|
def self.http_connection(uri)
|
25
25
|
http = Net::HTTP.new(uri.host, uri.port)
|
26
26
|
http.use_ssl = true if uri.scheme == 'https'
|
27
|
+
http.response_body_encoding = 'UTF-8' if http.respond_to?(:response_body_encoding=)
|
27
28
|
http.open_timeout = Unleash.configuration.timeout # in seconds
|
28
29
|
http.read_timeout = Unleash.configuration.timeout # in seconds
|
29
30
|
|
data/lib/unleash/variant.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Unleash
|
2
2
|
class Variant
|
3
|
-
attr_accessor :name, :enabled, :payload
|
3
|
+
attr_accessor :name, :enabled, :payload, :feature_enabled
|
4
4
|
|
5
5
|
def initialize(params = {})
|
6
6
|
raise ArgumentError, "Variant initializer requires a hash." unless params.is_a?(Hash)
|
@@ -8,16 +8,24 @@ module Unleash
|
|
8
8
|
self.name = params.values_at('name', :name).compact.first
|
9
9
|
self.enabled = params.values_at('enabled', :enabled).compact.first || false
|
10
10
|
self.payload = params.values_at('payload', :payload).compact.first
|
11
|
+
self.feature_enabled = params.values_at('feature_enabled', :feature_enabled).compact.first || false
|
11
12
|
|
12
13
|
raise ArgumentError, "Variant requires a name." if self.name.nil?
|
13
14
|
end
|
14
15
|
|
15
16
|
def to_s
|
16
|
-
|
17
|
+
# :nocov:
|
18
|
+
"<Variant: name=#{self.name},enabled=#{self.enabled},payload=#{self.payload},feature_enabled=#{self.feature_enabled}>"
|
19
|
+
# :nocov:
|
17
20
|
end
|
18
21
|
|
19
22
|
def ==(other)
|
20
|
-
self.name == other.name && self.enabled == other.enabled && self.payload == other.payload
|
23
|
+
self.name == other.name && self.enabled == other.enabled && self.payload == other.payload \
|
24
|
+
&& self.feature_enabled == other.feature_enabled
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.disabled_variant
|
28
|
+
Variant.new(name: 'disabled', enabled: false, feature_enabled: false)
|
21
29
|
end
|
22
30
|
end
|
23
31
|
end
|
data/lib/unleash/version.rb
CHANGED
data/lib/unleash.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'unleash/version'
|
2
|
+
require 'unleash/spec_version'
|
2
3
|
require 'unleash/configuration'
|
3
4
|
require 'unleash/strategies'
|
4
5
|
require 'unleash/context'
|
@@ -9,7 +10,7 @@ module Unleash
|
|
9
10
|
TIME_RESOLUTION = 3
|
10
11
|
|
11
12
|
class << self
|
12
|
-
attr_accessor :configuration, :toggle_fetcher, :
|
13
|
+
attr_accessor :configuration, :toggle_fetcher, :reporter, :logger, :engine
|
13
14
|
end
|
14
15
|
|
15
16
|
self.configuration = Unleash::Configuration.new
|
data/unleash-client.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.description = "This is the ruby client for Unleash, a powerful feature toggle system
|
14
14
|
that gives you a great overview over all feature toggles across all your applications and services."
|
15
15
|
|
16
|
-
spec.homepage = "https://github.com/unleash/unleash-
|
16
|
+
spec.homepage = "https://github.com/unleash/unleash-ruby-sdk"
|
17
17
|
|
18
18
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
19
|
f.match(%r{^(test|spec|features)/})
|
@@ -21,9 +21,13 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.bindir = 'bin'
|
22
22
|
spec.executables = spec.files.grep(%r{^bin/unleash}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ["lib"]
|
24
|
-
spec.required_ruby_version = ">= 2.
|
24
|
+
spec.required_ruby_version = ">= 2.7"
|
25
25
|
|
26
|
-
spec.add_dependency "
|
26
|
+
spec.add_dependency "ld-eventsource", "2.2.4" unless RUBY_ENGINE == 'jruby'
|
27
|
+
spec.add_dependency "yggdrasil-engine", "~> 1.0.4"
|
28
|
+
|
29
|
+
spec.add_dependency "base64", "~> 0.3.0"
|
30
|
+
spec.add_dependency "logger", "~> 1.6"
|
27
31
|
|
28
32
|
spec.add_development_dependency "bundler", "~> 2.1"
|
29
33
|
spec.add_development_dependency "rake", "~> 12.3"
|
@@ -33,7 +37,7 @@ Gem::Specification.new do |spec|
|
|
33
37
|
|
34
38
|
# rubocop:disable Gemspec/RubyVersionGlobalsUsage, Style/IfUnlessModifier
|
35
39
|
if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('3.0')
|
36
|
-
spec.add_development_dependency "rubocop", "~> 1.
|
40
|
+
spec.add_development_dependency "rubocop", "~> 1.75"
|
37
41
|
end
|
38
42
|
# rubocop:enable Gemspec/RubyVersionGlobalsUsage, Style/IfUnlessModifier
|
39
43
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Migrating to Unleash-Client-Ruby 6.0.0
|
2
|
+
|
3
|
+
This guide highlights the key changes you should be aware of when upgrading to v6.0.0 of the Unleash client.
|
4
|
+
|
5
|
+
## Custom strategy changes
|
6
|
+
|
7
|
+
In version 6+, custom strategies cannot override the built-in strategies. Specifically, strategies `applicationHostname`, `default`, `flexibleRollout`, `gradualRolloutRandom`, `gradualRolloutSessionId`, `gradualRolloutUserId`, `remoteAddress` or `userWithId` throw an error on startup. Previously, creating a custom strategy would only generate a warning in the logs.
|
8
|
+
|
9
|
+
The deprecated `register_custom_strategies` method has been removed. You can continue to [register custom strategies](./README.md#custom-strategies) using configuration.
|
10
|
+
|
11
|
+
## Direct access to strategy objects
|
12
|
+
|
13
|
+
**Note:** If you're not using the method `known_strategies` this section doesn't affect you
|
14
|
+
|
15
|
+
The objects for base strategies are no longer directly accessible via the SDK. The `known_strategies` method only returns custom strategies registered by the user. To check if a custom strategy will override either a built-in or custom strategy, use the `includes?` method (returns false if the name is available).
|
16
|
+
|
17
|
+
It is strongly discouraged to access or modify any properties of the built-in strategies other than the name. In version 6+, this is a hard requirement.
|
18
|
+
|
19
|
+
## ARM requirements
|
20
|
+
|
21
|
+
Version 6.0.0 introduces a new dependency on a native binary. Currently, only ARM binaries for macOS are distributed. If you require ARM support for Linux or Windows, please open a GitHub issue.
|
metadata
CHANGED
@@ -1,29 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unleash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renato Arruda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-08-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: ld-eventsource
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.2.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.2.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: yggdrasil-engine
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.4
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.4
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: base64
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.3.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.3.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: logger
|
15
57
|
requirement: !ruby/object:Gem::Requirement
|
16
58
|
requirements:
|
17
59
|
- - "~>"
|
18
60
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
61
|
+
version: '1.6'
|
20
62
|
type: :runtime
|
21
63
|
prerelease: false
|
22
64
|
version_requirements: !ruby/object:Gem::Requirement
|
23
65
|
requirements:
|
24
66
|
- - "~>"
|
25
67
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
68
|
+
version: '1.6'
|
27
69
|
- !ruby/object:Gem::Dependency
|
28
70
|
name: bundler
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +142,14 @@ dependencies:
|
|
100
142
|
requirements:
|
101
143
|
- - "~>"
|
102
144
|
- !ruby/object:Gem::Version
|
103
|
-
version: 1.
|
145
|
+
version: '1.75'
|
104
146
|
type: :development
|
105
147
|
prerelease: false
|
106
148
|
version_requirements: !ruby/object:Gem::Requirement
|
107
149
|
requirements:
|
108
150
|
- - "~>"
|
109
151
|
- !ruby/object:Gem::Version
|
110
|
-
version: 1.
|
152
|
+
version: '1.75'
|
111
153
|
- !ruby/object:Gem::Dependency
|
112
154
|
name: simplecov
|
113
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -160,11 +202,13 @@ files:
|
|
160
202
|
- bin/console
|
161
203
|
- bin/setup
|
162
204
|
- bin/unleash-client
|
205
|
+
- echo_client_spec_version.rb
|
163
206
|
- examples/bootstrap.rb
|
164
207
|
- examples/default-toggles.json
|
208
|
+
- examples/extending_unleash_with_opentelemetry.rb
|
165
209
|
- examples/simple.rb
|
210
|
+
- examples/streaming.rb
|
166
211
|
- lib/unleash.rb
|
167
|
-
- lib/unleash/activation_strategy.rb
|
168
212
|
- lib/unleash/bootstrap/configuration.rb
|
169
213
|
- lib/unleash/bootstrap/handler.rb
|
170
214
|
- lib/unleash/bootstrap/provider/base.rb
|
@@ -172,31 +216,21 @@ files:
|
|
172
216
|
- lib/unleash/bootstrap/provider/from_url.rb
|
173
217
|
- lib/unleash/client.rb
|
174
218
|
- lib/unleash/configuration.rb
|
175
|
-
- lib/unleash/constraint.rb
|
176
219
|
- lib/unleash/context.rb
|
177
|
-
- lib/unleash/feature_toggle.rb
|
178
|
-
- lib/unleash/metrics.rb
|
179
220
|
- lib/unleash/metrics_reporter.rb
|
180
221
|
- lib/unleash/scheduled_executor.rb
|
222
|
+
- lib/unleash/spec_version.rb
|
181
223
|
- lib/unleash/strategies.rb
|
182
|
-
- lib/unleash/
|
183
|
-
- lib/unleash/
|
184
|
-
- lib/unleash/strategy/default.rb
|
185
|
-
- lib/unleash/strategy/flexible_rollout.rb
|
186
|
-
- lib/unleash/strategy/gradual_rollout_random.rb
|
187
|
-
- lib/unleash/strategy/gradual_rollout_sessionid.rb
|
188
|
-
- lib/unleash/strategy/gradual_rollout_userid.rb
|
189
|
-
- lib/unleash/strategy/remote_address.rb
|
190
|
-
- lib/unleash/strategy/user_with_id.rb
|
191
|
-
- lib/unleash/strategy/util.rb
|
224
|
+
- lib/unleash/streaming_client_executor.rb
|
225
|
+
- lib/unleash/streaming_event_processor.rb
|
192
226
|
- lib/unleash/toggle_fetcher.rb
|
227
|
+
- lib/unleash/util/event_source_wrapper.rb
|
193
228
|
- lib/unleash/util/http.rb
|
194
229
|
- lib/unleash/variant.rb
|
195
|
-
- lib/unleash/variant_definition.rb
|
196
|
-
- lib/unleash/variant_override.rb
|
197
230
|
- lib/unleash/version.rb
|
198
231
|
- unleash-client.gemspec
|
199
|
-
|
232
|
+
- v6_MIGRATION_GUIDE.md
|
233
|
+
homepage: https://github.com/unleash/unleash-ruby-sdk
|
200
234
|
licenses:
|
201
235
|
- Apache-2.0
|
202
236
|
metadata: {}
|
@@ -208,14 +242,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
208
242
|
requirements:
|
209
243
|
- - ">="
|
210
244
|
- !ruby/object:Gem::Version
|
211
|
-
version: '2.
|
245
|
+
version: '2.7'
|
212
246
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
213
247
|
requirements:
|
214
248
|
- - ">="
|
215
249
|
- !ruby/object:Gem::Version
|
216
250
|
version: '0'
|
217
251
|
requirements: []
|
218
|
-
rubygems_version: 3.
|
252
|
+
rubygems_version: 3.5.22
|
219
253
|
signing_key:
|
220
254
|
specification_version: 4
|
221
255
|
summary: Unleash feature toggle client.
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module Unleash
|
2
|
-
class ActivationStrategy
|
3
|
-
attr_accessor :name, :params, :constraints, :disabled
|
4
|
-
|
5
|
-
def initialize(name, params, constraints = [])
|
6
|
-
self.name = name
|
7
|
-
self.disabled = false
|
8
|
-
|
9
|
-
if params.is_a?(Hash)
|
10
|
-
self.params = params
|
11
|
-
elsif params.nil?
|
12
|
-
self.params = {}
|
13
|
-
else
|
14
|
-
Unleash.logger.warn "Invalid params provided for ActivationStrategy (params:#{params})"
|
15
|
-
self.params = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
if constraints.is_a?(Array) && constraints.each{ |c| c.is_a?(Constraint) }
|
19
|
-
self.constraints = constraints
|
20
|
-
else
|
21
|
-
Unleash.logger.warn "Invalid constraints provided for ActivationStrategy (contraints: #{constraints})"
|
22
|
-
self.disabled = true
|
23
|
-
self.constraints = []
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def matches_context?(context)
|
28
|
-
self.constraints.any?{ |c| c.matches_context? context }
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|