unleash 4.4.1 → 4.4.3

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: e7e1d111b5560a8236c52c1b1744f32724fdd0b26d02af16da707efe2869be3e
4
- data.tar.gz: 402580857880d3508ad7b46afbc47b74c696bb6ad5360a48e4254f35ecd48f05
3
+ metadata.gz: 910ddad70479cae68918b7400b4ddc6d0c71f9448d8524072c318d6c353c4f52
4
+ data.tar.gz: 1d75ed31736627ea30c2bbc9be7903c9dfa19dc4691c07de885dd87a8eb94c85
5
5
  SHA512:
6
- metadata.gz: ed380682c17c90cea0d8b79ba7b05f20b053eb20fd3d293f93e3b2356a264ab386fcee3b91b6ec6507965fb23e922f1e9d50cae2bd880973d9111413abda0572
7
- data.tar.gz: 0ba69ee86b9dc60e65aac73023e9e39c1a93d56579fee7c3f990d4e944259a879ba66058e8614cc41c9dc22a41cc4ab5bf8824e7db24d3e8a5cbc8b5c4fcb4cb
6
+ metadata.gz: aec46ef764fcb138d34baa7c6832ff1865be4dac1f6f004ab928e8447ecde701ec82bf2069c69e62b2404706bf029c1743a3dc2322b5e7409135aba498cdf80e
7
+ data.tar.gz: d1a529a53cbd934c4aae24919352fc670b27b8cb0a9ccb2bde20deafa3eb3adf679e7c49ced246258547f68a400a10a1da214bc07a19e153ffb0af60fcea8961
@@ -10,11 +10,11 @@ jobs:
10
10
  timeout-minutes: 30
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
- - uses: actions/checkout@v2
13
+ - uses: actions/checkout@v3
14
14
  - name: Set up Ruby
15
15
  uses: ruby/setup-ruby@v1
16
16
  with:
17
- ruby-version: "2.7"
17
+ ruby-version: "3.0"
18
18
  bundler-cache: true
19
19
  - name: Run RuboCop
20
20
  run: bundle exec rubocop
@@ -31,12 +31,15 @@ jobs:
31
31
  - jruby-9.4
32
32
  - jruby-9.3
33
33
  - jruby-9.2
34
+ - 3.2
34
35
  - 3.1
35
36
  - '3.0'
36
37
  - 2.7
37
38
  - 2.6
38
39
  - 2.5
39
40
 
41
+ needs:
42
+ - lint
40
43
  steps:
41
44
  - uses: actions/checkout@v3
42
45
  - name: Set up Ruby ${{ matrix.ruby-version }}
data/.rubocop.yml CHANGED
@@ -6,10 +6,13 @@ AllCops:
6
6
  Naming/PredicateName:
7
7
  AllowedMethods:
8
8
  - is_enabled?
9
+ - is_disabled?
9
10
 
10
11
 
11
12
  Metrics/ClassLength:
12
13
  Max: 135
14
+ CountAsOne:
15
+ - 'method_call'
13
16
  Layout/LineLength:
14
17
  Max: 140
15
18
  Metrics/MethodLength:
data/README.md CHANGED
@@ -10,6 +10,7 @@ Leverage the [Unleash Server](https://github.com/Unleash/unleash) for powerful f
10
10
 
11
11
  ## Supported Ruby Interpreters
12
12
 
13
+ * MRI 3.2
13
14
  * MRI 3.1
14
15
  * MRI 3.0
15
16
  * MRI 2.7
@@ -85,12 +86,12 @@ Argument | Description | Required? | Type | Default Value|
85
86
  `url` | Unleash server URL. | Y | String | N/A |
86
87
  `app_name` | Name of your program. | Y | String | N/A |
87
88
  `instance_id` | Identifier for the running instance of program. Important so you can trace back to where metrics are being collected from. **Highly recommended be be set.** | N | String | random UUID |
88
- `environment` | Environment the program is running on. Could be for example `prod` or `dev`. Not yet in use. | N | String | `default` |
89
+ `environment` | Unleash context option. Could be for example `prod` or `dev`. Not yet in use. **Not** the same as the SDK's [Unleash environment](https://docs.getunleash.io/reference/environments). | N | String | `default` |
89
90
  `project_name` | Name of the project to retrieve features from. If not set, all feature flags will be retrieved. | N | String | nil |
90
91
  `refresh_interval` | How often the unleash client should check with the server for configuration changes. | N | Integer | 15 |
91
92
  `metrics_interval` | How often the unleash client should send metrics to server. | N | Integer | 60 |
92
- `disable_client` | Disables all communication with the Unleash server, effectively taking it *offline*. If set, `is_enabled?` will always answer with the `default_value` and configuration validation is skipped. Defeats the entire purpose of using unleash, but can be useful in when running tests. | N | Boolean | `false` |
93
- `disable_metrics` | Disables sending metrics to Unleash server. | N | Boolean | `false` |
93
+ `disable_client` | Disables all communication with the Unleash server, effectively taking it *offline*. If set, `is_enabled?` will always answer with the `default_value` and configuration validation is skipped. Will also forcefully set `disable_metrics` to `true`. Defeats the entire purpose of using unleash, except when running tests. | N | Boolean | `false` |
94
+ `disable_metrics` | Disables sending metrics to Unleash server. If the `disable_client` option is set to `true`, then this option will also be set to `true`, regardless of the value provided. | N | Boolean | `false` |
94
95
  `custom_http_headers` | Custom headers to send to Unleash. As of Unleash v4.0.0, the `Authorization` header is required. For example: `{'Authorization': '<API token>'}` | N | Hash/Proc | {} |
95
96
  `timeout` | How long to wait for the connection to be established or wait in reading state (open_timeout/read_timeout) | N | Integer | 30 |
96
97
  `retry_limit` | How many consecutive failures in connecting to the Unleash server are allowed before giving up. The default is to retry indefinitely. | N | Float::INFINITY | 5 |
@@ -124,6 +125,12 @@ if @unleash.is_enabled?(feature_name, unleash_context)
124
125
  else
125
126
  puts " #{feature_name} is disabled according to unleash"
126
127
  end
128
+
129
+ if @unleash.is_disabled?(feature_name, unleash_context)
130
+ puts " #{feature_name} is disabled according to unleash"
131
+ else
132
+ puts " #{feature_name} is enabled according to unleash"
133
+ end
127
134
  ```
128
135
 
129
136
  ## Usage in a Rails Application
@@ -138,7 +145,6 @@ Unleash.configure do |config|
138
145
  config.url = 'https://unleash.herokuapp.com/api'
139
146
  # config.instance_id = "#{Socket.gethostname}"
140
147
  config.logger = Rails.logger
141
- config.environment = Rails.env
142
148
  end
143
149
 
144
150
  UNLEASH = Unleash::Client.new
@@ -173,7 +179,6 @@ Then you may keep the client configuration still in `config/initializers/unleash
173
179
  ```ruby
174
180
  Unleash.configure do |config|
175
181
  config.app_name = Rails.application.class.parent.to_s
176
- config.environment = Rails.env
177
182
  config.url = 'https://unleash.herokuapp.com/api'
178
183
  config.custom_http_headers = {'Authorization': '<API token>'}
179
184
  end
@@ -221,7 +226,6 @@ on_worker_boot do
221
226
 
222
227
  ::UNLEASH = Unleash::Client.new(
223
228
  app_name: 'my_rails_app',
224
- environment: 'development',
225
229
  url: 'https://unleash.herokuapp.com/api',
226
230
  custom_http_headers: {'Authorization': '<API token>'},
227
231
  )
@@ -247,7 +251,6 @@ PhusionPassenger.on_event(:starting_worker_process) do |forked|
247
251
  config.app_name = Rails.application.class.parent.to_s
248
252
  # config.instance_id = "#{Socket.gethostname}"
249
253
  config.logger = Rails.logger
250
- config.environment = Rails.env
251
254
  config.url = 'https://unleash.herokuapp.com/api'
252
255
  config.custom_http_headers = {'Authorization': '<API token>'}
253
256
  end
@@ -313,13 +316,31 @@ if Rails.configuration.unleash.is_enabled? "AwesomeFeature", @unleash_context
313
316
  end
314
317
  ```
315
318
 
319
+ If you don't want to check a feature is disabled with `unless`, you can also use `is_disabled?`:
320
+
321
+ ```ruby
322
+ # so instead of:
323
+ unless UNLEASH.is_enabled? "AwesomeFeature", @unleash_context
324
+ puts "AwesomeFeature is disabled"
325
+ end
326
+
327
+ # it might be more intelligible:
328
+ if UNLEASH.is_disabled? "AwesomeFeature", @unleash_context
329
+ puts "AwesomeFeature is disabled"
330
+ end
331
+ ```
332
+
316
333
  If the feature is not found in the server, it will by default return false.
317
- However you can override that by setting the default return value to `true`:
334
+ However, you can override that by setting the default return value to `true`:
318
335
 
319
336
  ```ruby
320
337
  if UNLEASH.is_enabled? "AwesomeFeature", @unleash_context, true
321
338
  puts "AwesomeFeature is enabled by default"
322
339
  end
340
+ # or
341
+ if UNLEASH.is_disabled? "AwesomeFeature", @unleash_context, true
342
+ puts "AwesomeFeature is disabled by default"
343
+ end
323
344
  ```
324
345
 
325
346
  Another possibility is to send a block, [Lambda](https://ruby-doc.org/core-3.0.1/Kernel.html#method-i-lambda) or [Proc](https://ruby-doc.org/core-3.0.1/Proc.html#method-i-yield)
@@ -342,7 +363,7 @@ awesomeness = 10
342
363
  @unleash_context.properties[:coolness] = 10
343
364
 
344
365
  if UNLEASH.is_enabled?("AwesomeFeature", @unleash_context) { |feat, ctx| awesomeness >= 6 && ctx.properties[:coolness] >= 8 }
345
- puts "AwesomeFeature is enabled by default if both the user has a high enought coolness and the application has a high enough awesomeness"
366
+ puts "AwesomeFeature is enabled by default if both the user has a high enough coolness and the application has a high enough awesomeness"
346
367
  end
347
368
  ```
348
369
 
@@ -351,12 +372,12 @@ Note:
351
372
  - The client will evaluate the fallback function once per call of `is_enabled()`.
352
373
  Please keep this in mind when creating your fallback function!
353
374
  - The returned value of the block should be a boolean.
354
- However the client will coerce the result to boolean via `!!`.
375
+ However, the client will coerce the result to boolean via `!!`.
355
376
  - If both a `default_value` and `fallback_function` are supplied,
356
377
  the client will define the default value by `OR`ing the default value and the output of the fallback function.
357
378
 
358
379
 
359
- Alternatively by using `if_enabled` you can send a code block to be executed as a parameter:
380
+ Alternatively by using `if_enabled` (or `if_disabled`) you can send a code block to be executed as a parameter:
360
381
 
361
382
  ```ruby
362
383
  UNLEASH.if_enabled "AwesomeFeature", @unleash_context, true do
@@ -364,7 +385,7 @@ UNLEASH.if_enabled "AwesomeFeature", @unleash_context, true do
364
385
  end
365
386
  ```
366
387
 
367
- Note: `if_enabled` only supports `default_value`, but not `fallback_function`.
388
+ Note: `if_enabled` (and `if_disabled`) only support `default_value`, but not `fallback_function`.
368
389
 
369
390
  ##### Variations
370
391
 
@@ -444,6 +465,9 @@ Method Name | Description | Return Type |
444
465
  `is_enabled?` | Check if feature toggle is to be enabled or not. | Boolean |
445
466
  `enabled?` | Alias to the `is_enabled?` method. But more ruby idiomatic. | Boolean |
446
467
  `if_enabled` | Run a code block, if a feature is enabled. | `yield` |
468
+ `is_disabled?` | Check if feature toggle is to be enabled or not. | Boolean |
469
+ `disabled?` | Alias to the `is_disabled?` method. But more ruby idiomatic. | Boolean |
470
+ `if_disabled` | Run a code block, if a feature is disabled. | `yield` |
447
471
  `get_variant` | Get variant for a given feature | `Unleash::Variant` |
448
472
  `shutdown` | Save metrics to disk, flush metrics to server, and then kill ToggleFetcher and MetricsReporter threads. A safe shutdown. Not really useful in long running applications, like web applications. | nil |
449
473
  `shutdown!` | Kill ToggleFetcher and MetricsReporter threads immediately. | nil |
@@ -482,7 +506,7 @@ In order for strategy to work correctly it should support two methods `name` and
482
506
  ```ruby
483
507
  class MyCustomStrategy
484
508
  def name
485
- 'muCustomStrategy'
509
+ 'myCustomStrategy'
486
510
  end
487
511
 
488
512
  def is_enabled?(params = {}, context = nil)
@@ -497,15 +521,19 @@ end
497
521
 
498
522
  ## Development
499
523
 
500
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
524
+ After checking out the repo, run `bin/setup` to install dependencies.
525
+ Then, run `rake spec` to run the tests.
526
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
501
527
 
502
- This SDK is also built against the Unleash Client Specification tests. To run the Ruby SDK against this test suite, you'll need to have a copy on your machine, you can clone the repository directly using:
528
+ This SDK is also built against the Unleash Client Specification tests.
529
+ To run the Ruby SDK against this test suite, you'll need to have a copy on your machine, you can clone the repository directly using:
503
530
 
504
531
  `git clone --depth 5 --branch v4.2.2 https://github.com/Unleash/client-specification.git client-specification`
505
532
 
506
533
  After doing this, `rake spec` will also run the client specification tests.
507
534
 
508
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
535
+ To install this gem onto your local machine, run `bundle exec rake install`.
536
+ To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
509
537
 
510
538
 
511
539
  ## Contributing
data/bin/console CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
+ require "unleash"
4
5
  require "unleash/client"
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
@@ -21,6 +21,8 @@ module Unleash
21
21
  Unleash.toggle_fetcher = Unleash::ToggleFetcher.new
22
22
  if Unleash.configuration.disable_client
23
23
  Unleash.logger.warn "Unleash::Client is disabled! Will only return default (or bootstrapped if available) results!"
24
+ Unleash.logger.warn "Unleash::Client is disabled! Metrics and MetricsReporter are also disabled!"
25
+ Unleash.configuration.disable_metrics = true
24
26
  return
25
27
  end
26
28
 
@@ -50,22 +52,28 @@ module Unleash
50
52
  toggle.is_enabled?(context)
51
53
  end
52
54
 
55
+ def is_disabled?(feature, context = nil, default_value_param = true, &fallback_blk)
56
+ !is_enabled?(feature, context, !default_value_param, &fallback_blk)
57
+ end
58
+
53
59
  # enabled? is a more ruby idiomatic method name than is_enabled?
54
60
  alias enabled? is_enabled?
61
+ # disabled? is a more ruby idiomatic method name than is_disabled?
62
+ alias disabled? is_disabled?
55
63
 
56
64
  # execute a code block (passed as a parameter), if is_enabled? is true.
57
65
  def if_enabled(feature, context = nil, default_value = false, &blk)
58
66
  yield(blk) if is_enabled?(feature, context, default_value)
59
67
  end
60
68
 
69
+ # execute a code block (passed as a parameter), if is_disabled? is true.
70
+ def if_disabled(feature, context = nil, default_value = true, &blk)
71
+ yield(blk) if is_disabled?(feature, context, default_value)
72
+ end
73
+
61
74
  def get_variant(feature, context = Unleash::Context.new, fallback_variant = disabled_variant)
62
75
  Unleash.logger.debug "Unleash::Client.get_variant for feature: #{feature} with context #{context}"
63
76
 
64
- if Unleash.configuration.disable_client
65
- Unleash.logger.debug "unleash_client is disabled! Always returning #{fallback_variant} for feature #{feature}!"
66
- return fallback_variant
67
- end
68
-
69
77
  toggle_as_hash = Unleash&.toggles&.select{ |toggle| toggle['name'] == feature }&.first
70
78
 
71
79
  if toggle_as_hash.nil?
@@ -23,6 +23,11 @@ module Unleash
23
23
  ",app_name=#{@app_name},environment=#{@environment}>"
24
24
  end
25
25
 
26
+ def to_h
27
+ ATTRS.map{ |attr| [attr, self.send(attr)] }.to_h.merge(properties: @properties)
28
+ end
29
+
30
+ # returns the value found for the key in the context, or raises a KeyError exception if not found.
26
31
  def get_by_name(name)
27
32
  normalized_name = underscore(name).to_sym
28
33
 
@@ -97,10 +97,15 @@ module Unleash
97
97
  end
98
98
 
99
99
  def variant_salt(context, stickiness = "default")
100
- return context.get_by_name(stickiness) unless stickiness == "default"
101
- return context.user_id unless context.user_id.to_s.empty?
102
- return context.session_id unless context.session_id.to_s.empty?
103
- return context.remote_address unless context.remote_address.to_s.empty?
100
+ begin
101
+ return context.get_by_name(stickiness) if !context.nil? && stickiness != "default"
102
+ rescue KeyError
103
+ Unleash.logger.warn "Custom stickiness key (#{stickiness}) not found in the provided context #{context}. " \
104
+ "Falling back to default behavior."
105
+ end
106
+ return context.user_id unless context&.user_id.to_s.empty?
107
+ return context.session_id unless context&.session_id.to_s.empty?
108
+ return context.remote_address unless context&.remote_address.to_s.empty?
104
109
 
105
110
  SecureRandom.random_number
106
111
  end
@@ -26,9 +26,9 @@ module Unleash
26
26
  self.features_lock.synchronize do
27
27
  self.features[feature] = { yes: 0, no: 0 } unless self.features.include? feature
28
28
  self.features[feature][choice] += 1
29
- self.features[feature]['variant'] = {} unless self.features[feature].include? 'variant'
30
- self.features[feature]['variant'][variant] = 0 unless self.features[feature]['variant'].include? variant
31
- self.features[feature]['variant'][variant] += 1
29
+ self.features[feature]['variants'] = {} unless self.features[feature].include? 'variants'
30
+ self.features[feature]['variants'][variant] = 0 unless self.features[feature]['variants'].include? variant
31
+ self.features[feature]['variants'][variant] += 1
32
32
  end
33
33
  end
34
34
 
@@ -1,3 +1,3 @@
1
1
  module Unleash
2
- VERSION = "4.4.1".freeze
2
+ VERSION = "4.4.3".freeze
3
3
  end
@@ -23,15 +23,20 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
  spec.required_ruby_version = ">= 2.5"
25
25
 
26
- spec.add_dependency "murmurhash3", "~> 0.1.6"
26
+ spec.add_dependency "murmurhash3", "~> 0.1.7"
27
27
 
28
28
  spec.add_development_dependency "bundler", "~> 2.1"
29
29
  spec.add_development_dependency "rake", "~> 12.3"
30
- spec.add_development_dependency "rspec", "~> 3.9"
30
+ spec.add_development_dependency "rspec", "~> 3.12"
31
31
  spec.add_development_dependency "rspec-json_expectations", "~> 2.2"
32
- spec.add_development_dependency "webmock", "~> 3.8"
32
+ spec.add_development_dependency "webmock", "~> 3.18.1"
33
+
34
+ # rubocop:disable Gemspec/RubyVersionGlobalsUsage, Style/IfUnlessModifier
35
+ if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('3.0')
36
+ spec.add_development_dependency "rubocop", "~> 1.51.0"
37
+ end
38
+ # rubocop:enable Gemspec/RubyVersionGlobalsUsage, Style/IfUnlessModifier
33
39
 
34
- spec.add_development_dependency "rubocop", "~> 1.28.2"
35
40
  spec.add_development_dependency "simplecov", "~> 0.21.2"
36
41
  spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"
37
42
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unleash
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.1
4
+ version: 4.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Renato Arruda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-07 00:00:00.000000000 Z
11
+ date: 2023-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: murmurhash3
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.6
19
+ version: 0.1.7
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.6
26
+ version: 0.1.7
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.9'
61
+ version: '3.12'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.9'
68
+ version: '3.12'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec-json_expectations
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,28 +86,28 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.8'
89
+ version: 3.18.1
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.8'
96
+ version: 3.18.1
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 1.28.2
103
+ version: 1.51.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 1.28.2
110
+ version: 1.51.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: simplecov
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -214,7 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
214
  - !ruby/object:Gem::Version
215
215
  version: '0'
216
216
  requirements: []
217
- rubygems_version: 3.3.5
217
+ rubygems_version: 3.4.10
218
218
  signing_key:
219
219
  specification_version: 4
220
220
  summary: Unleash feature toggle client.