determinator 2.5.1 → 2.7.0

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: 4466edc3643125ca6b84591b4db51083d215c5c6ea8201694e99d16e403eab24
4
- data.tar.gz: 326d45e3f0ac249e5a358ee3911c1da4da01db81c14ab1b3c827a8fd5d0f4ef9
3
+ metadata.gz: dffc736e777d38ceafbe8ce45d0a01f960341a542a2b93b6ba13b77f1479d291
4
+ data.tar.gz: 7be7ecbd850faac8009e031d41eea1d9679d5f2c43923cbc8ad688c6c1411f3a
5
5
  SHA512:
6
- metadata.gz: c83ad23860f0d5565618e3cfbf1f9975763f3f64c0db49668fa2259aae06c972689e000538a734571906edbf766c8d1d46e58ad2d7c657461c76759768f37bfa
7
- data.tar.gz: 777556d4606d6a10514b5f7c6311e498117845f9bf5bc3bd1be7f8c47cee837fb17243348d11ee0f2fff3931493e97e65cb06608dcbc9b435916aabad07e69f1
6
+ metadata.gz: 5b959c8460720151fd7455f1bbc556af6f61f327c7092bad148d52bc9141c3e5144c17a7c6cb45c483322f9dc65ee047ceccc1a048eea15e46544f6aa4fb06e1
7
+ data.tar.gz: b8b08c82db627c37d8630dd56111d0361b3c5a5874286d447015ac98d0d25a2421631f589f4438b26d71bc9ed58f5141d8084563dd37c24c7f5ca71faac62156
@@ -0,0 +1,33 @@
1
+ name: Ruby Gem
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ - name: Set git user
15
+ run: |
16
+ git config user.email "rooci@deliveroo.co.uk"
17
+ git config user.name "Determinator Release Github Action"
18
+ - name: Set up Ruby 2.6
19
+ uses: actions/setup-ruby@v1
20
+ with:
21
+ ruby-version: 2.6.x
22
+
23
+ - name: Publish to RubyGems
24
+ run: |
25
+ mkdir -p $HOME/.gem
26
+ touch $HOME/.gem/credentials
27
+ chmod 0600 $HOME/.gem/credentials
28
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
29
+ gem install bundler
30
+ bundle install --jobs 4 --retry 3
31
+ rake release
32
+ env:
33
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ # 2.7.0
2
+
3
+ ⚠️ This release includes breaking changes ⚠️
4
+
5
+ Interface change:
6
+ - Constraints which are not arrays of strings are no longer accepted; if present, the library returns false and logs an error.
7
+
8
+ # 2.6.0
9
+
10
+ Interface change:
11
+ - A `feature_cache` is now required to use Determinator. See the `examples/determinator-rails/config/initializers/determinator.rb` for a quick start.
12
+
13
+ # 2.5.4
14
+
15
+ Bug fix:
16
+ - Apply app_version logic to structured request.app_version too
17
+
18
+ # 2.5.3
19
+
20
+ Bug fix:
21
+ - Avoid errors when updating the gem and using persistent cache resulting in null fixed_determinations
22
+
23
+ # 2.5.2
24
+
25
+ Feature:
26
+ - Add structured_bucket to Feature
27
+ - Add `#retrieve` method to the Control
28
+ - Add optional `feature` argument to `feature_flag_on?` and `which_variant`, to reuse an existing feature
29
+
1
30
  # 2.5.1
2
31
 
3
32
  Feature:
data/determinator.gemspec CHANGED
@@ -23,12 +23,12 @@ Gem::Specification.new do |spec|
23
23
  spec.add_runtime_dependency "faraday"
24
24
  spec.add_runtime_dependency "semantic", "~> 1.6"
25
25
 
26
- spec.add_development_dependency "bundler", "~> 2.1.4"
27
- spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "bundler"
27
+ spec.add_development_dependency "rake", "~> 12.0"
28
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
29
  spec.add_development_dependency "rspec-its", "~> 1.2"
30
30
  spec.add_development_dependency "guard-rspec", "~> 4.7"
31
- spec.add_development_dependency "factory_girl", "~> 4.8"
31
+ spec.add_development_dependency "factory_bot", "~> 4.8"
32
32
  spec.add_development_dependency 'webmock'
33
- spec.add_development_dependency "sidekiq"
33
+ spec.add_development_dependency 'sidekiq'
34
34
  end
@@ -1,8 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rails', '~> 5.0.2'
3
+ gem 'rails', '~> 5.1'
4
4
  gem 'puma', '~> 3.0'
5
- gem 'sidekiq'
6
5
 
7
6
  gem 'determinator', path: '../..'
8
7
 
@@ -1,140 +1,144 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- determinator (1.2.0)
4
+ determinator (2.6.0)
5
5
  faraday
6
+ semantic (~> 1.6)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
10
- actioncable (5.0.7)
11
- actionpack (= 5.0.7)
12
- nio4r (>= 1.2, < 3.0)
13
- websocket-driver (~> 0.6.1)
14
- actionmailer (5.0.7)
15
- actionpack (= 5.0.7)
16
- actionview (= 5.0.7)
17
- activejob (= 5.0.7)
11
+ actioncable (5.2.4.4)
12
+ actionpack (= 5.2.4.4)
13
+ nio4r (~> 2.0)
14
+ websocket-driver (>= 0.6.1)
15
+ actionmailer (5.2.4.4)
16
+ actionpack (= 5.2.4.4)
17
+ actionview (= 5.2.4.4)
18
+ activejob (= 5.2.4.4)
18
19
  mail (~> 2.5, >= 2.5.4)
19
20
  rails-dom-testing (~> 2.0)
20
- actionpack (5.0.7)
21
- actionview (= 5.0.7)
22
- activesupport (= 5.0.7)
23
- rack (~> 2.0)
24
- rack-test (~> 0.6.3)
21
+ actionpack (5.2.4.4)
22
+ actionview (= 5.2.4.4)
23
+ activesupport (= 5.2.4.4)
24
+ rack (~> 2.0, >= 2.0.8)
25
+ rack-test (>= 0.6.3)
25
26
  rails-dom-testing (~> 2.0)
26
27
  rails-html-sanitizer (~> 1.0, >= 1.0.2)
27
- actionview (5.0.7)
28
- activesupport (= 5.0.7)
28
+ actionview (5.2.4.4)
29
+ activesupport (= 5.2.4.4)
29
30
  builder (~> 3.1)
30
- erubis (~> 2.7.0)
31
+ erubi (~> 1.4)
31
32
  rails-dom-testing (~> 2.0)
32
33
  rails-html-sanitizer (~> 1.0, >= 1.0.3)
33
- activejob (5.0.7)
34
- activesupport (= 5.0.7)
34
+ activejob (5.2.4.4)
35
+ activesupport (= 5.2.4.4)
35
36
  globalid (>= 0.3.6)
36
- activemodel (5.0.7)
37
- activesupport (= 5.0.7)
38
- activerecord (5.0.7)
39
- activemodel (= 5.0.7)
40
- activesupport (= 5.0.7)
41
- arel (~> 7.0)
42
- activesupport (5.0.7)
37
+ activemodel (5.2.4.4)
38
+ activesupport (= 5.2.4.4)
39
+ activerecord (5.2.4.4)
40
+ activemodel (= 5.2.4.4)
41
+ activesupport (= 5.2.4.4)
42
+ arel (>= 9.0)
43
+ activestorage (5.2.4.4)
44
+ actionpack (= 5.2.4.4)
45
+ activerecord (= 5.2.4.4)
46
+ marcel (~> 0.3.1)
47
+ activesupport (5.2.4.4)
43
48
  concurrent-ruby (~> 1.0, >= 1.0.2)
44
49
  i18n (>= 0.7, < 2)
45
50
  minitest (~> 5.1)
46
51
  tzinfo (~> 1.1)
47
- arel (7.1.4)
48
- builder (3.2.3)
49
- byebug (10.0.2)
50
- concurrent-ruby (1.0.5)
51
- connection_pool (2.2.2)
52
- crass (1.0.4)
53
- dotenv (2.4.0)
54
- dotenv-rails (2.4.0)
55
- dotenv (= 2.4.0)
56
- railties (>= 3.2, < 6.0)
57
- erubis (2.7.0)
58
- faraday (0.15.4)
52
+ arel (9.0.0)
53
+ builder (3.2.4)
54
+ byebug (11.1.3)
55
+ concurrent-ruby (1.1.8)
56
+ crass (1.0.6)
57
+ dotenv (2.7.6)
58
+ dotenv-rails (2.7.6)
59
+ dotenv (= 2.7.6)
60
+ railties (>= 3.2)
61
+ erubi (1.10.0)
62
+ faraday (1.3.0)
63
+ faraday-net_http (~> 1.0)
59
64
  multipart-post (>= 1.2, < 3)
60
- globalid (0.4.1)
65
+ ruby2_keywords
66
+ faraday-net_http (1.0.1)
67
+ globalid (0.4.2)
61
68
  activesupport (>= 4.2.0)
62
- i18n (1.0.1)
69
+ i18n (1.8.7)
63
70
  concurrent-ruby (~> 1.0)
64
- loofah (2.2.2)
71
+ loofah (2.9.0)
65
72
  crass (~> 1.0.2)
66
73
  nokogiri (>= 1.5.9)
67
- mail (2.7.0)
74
+ mail (2.7.1)
68
75
  mini_mime (>= 0.1.1)
69
- method_source (0.9.0)
70
- mini_mime (1.0.0)
71
- mini_portile2 (2.3.0)
72
- minitest (5.11.3)
73
- multipart-post (2.0.0)
74
- nio4r (2.3.1)
75
- nokogiri (1.8.2)
76
- mini_portile2 (~> 2.3.0)
77
- puma (3.11.4)
78
- rack (2.0.5)
79
- rack-protection (2.0.3)
80
- rack
81
- rack-test (0.6.3)
82
- rack (>= 1.0)
83
- rails (5.0.7)
84
- actioncable (= 5.0.7)
85
- actionmailer (= 5.0.7)
86
- actionpack (= 5.0.7)
87
- actionview (= 5.0.7)
88
- activejob (= 5.0.7)
89
- activemodel (= 5.0.7)
90
- activerecord (= 5.0.7)
91
- activesupport (= 5.0.7)
76
+ marcel (0.3.3)
77
+ mimemagic (~> 0.3.2)
78
+ method_source (1.0.0)
79
+ mimemagic (0.3.5)
80
+ mini_mime (1.0.2)
81
+ minitest (5.14.3)
82
+ multipart-post (2.1.1)
83
+ nio4r (2.5.4)
84
+ nokogiri (1.11.1-x86_64-darwin)
85
+ racc (~> 1.4)
86
+ puma (3.12.6)
87
+ racc (1.5.2)
88
+ rack (2.2.3)
89
+ rack-test (1.1.0)
90
+ rack (>= 1.0, < 3)
91
+ rails (5.2.4.4)
92
+ actioncable (= 5.2.4.4)
93
+ actionmailer (= 5.2.4.4)
94
+ actionpack (= 5.2.4.4)
95
+ actionview (= 5.2.4.4)
96
+ activejob (= 5.2.4.4)
97
+ activemodel (= 5.2.4.4)
98
+ activerecord (= 5.2.4.4)
99
+ activestorage (= 5.2.4.4)
100
+ activesupport (= 5.2.4.4)
92
101
  bundler (>= 1.3.0)
93
- railties (= 5.0.7)
102
+ railties (= 5.2.4.4)
94
103
  sprockets-rails (>= 2.0.0)
95
104
  rails-dom-testing (2.0.3)
96
105
  activesupport (>= 4.2.0)
97
106
  nokogiri (>= 1.6)
98
- rails-html-sanitizer (1.0.4)
99
- loofah (~> 2.2, >= 2.2.2)
100
- railties (5.0.7)
101
- actionpack (= 5.0.7)
102
- activesupport (= 5.0.7)
107
+ rails-html-sanitizer (1.3.0)
108
+ loofah (~> 2.3)
109
+ railties (5.2.4.4)
110
+ actionpack (= 5.2.4.4)
111
+ activesupport (= 5.2.4.4)
103
112
  method_source
104
113
  rake (>= 0.8.7)
105
- thor (>= 0.18.1, < 2.0)
106
- rake (12.3.1)
107
- redis (4.0.1)
108
- sidekiq (5.1.3)
109
- concurrent-ruby (~> 1.0)
110
- connection_pool (~> 2.2, >= 2.2.0)
111
- rack-protection (>= 1.5.0)
112
- redis (>= 3.3.5, < 5)
113
- sprockets (3.7.1)
114
+ thor (>= 0.19.0, < 2.0)
115
+ rake (13.0.3)
116
+ ruby2_keywords (0.0.4)
117
+ semantic (1.6.1)
118
+ sprockets (4.0.2)
114
119
  concurrent-ruby (~> 1.0)
115
120
  rack (> 1, < 3)
116
- sprockets-rails (3.2.1)
121
+ sprockets-rails (3.2.2)
117
122
  actionpack (>= 4.0)
118
123
  activesupport (>= 4.0)
119
124
  sprockets (>= 3.0.0)
120
- thor (0.20.0)
125
+ thor (1.1.0)
121
126
  thread_safe (0.3.6)
122
- tzinfo (1.2.5)
127
+ tzinfo (1.2.9)
123
128
  thread_safe (~> 0.1)
124
- websocket-driver (0.6.5)
129
+ websocket-driver (0.7.3)
125
130
  websocket-extensions (>= 0.1.0)
126
- websocket-extensions (0.1.3)
131
+ websocket-extensions (0.1.5)
127
132
 
128
133
  PLATFORMS
129
- ruby
134
+ x86_64-darwin-19
130
135
 
131
136
  DEPENDENCIES
132
137
  byebug
133
138
  determinator!
134
139
  dotenv-rails
135
140
  puma (~> 3.0)
136
- rails (~> 5.0.2)
137
- sidekiq
141
+ rails (~> 5.1)
138
142
 
139
143
  BUNDLED WITH
140
- 1.17.3
144
+ 2.2.7
@@ -5,9 +5,13 @@ class IndexController < ApplicationController
5
5
 
6
6
  message = [
7
7
  is_colloquial ? "hi world" : "hello world",
8
- emoji
8
+ (emoji if emoji)
9
9
  ].compact.join(" ")
10
10
 
11
- render json: { welcome: message }
11
+ explain = "An experiment and a feature flag are being checked for the user with guid #{guid}. "
12
+ explain += "The feature flag (colloquial_welcome) is #{is_colloquial ? 'on' : 'off'}. "
13
+ explain += "The experiment (welcome_emoji) returned #{emoji}#{", so is omitted" unless emoji}."
14
+
15
+ render json: { welcome: message, explanation: explain }
12
16
  end
13
17
  end
@@ -1,7 +1,9 @@
1
- require 'determinator/retrieve/dynaconf'
1
+ require 'determinator/retrieve/file'
2
2
  require 'active_support/cache'
3
3
 
4
- retrieval = Determinator::Retrieve::Dynaconf.new(base_url: 'http://localhost:2345', service_name: 'determinator-rails')
4
+ # File retriever just for example; use a Dynaconf retriever in your app
5
+ # retrieval = Determinator::Retrieve::Dynaconf.new(base_url: ENV['DYNACONF_URL'], service_name: 'determinator-rails')
6
+ retrieval = Determinator::Retrieve::File.new(root: File.join(__dir__, "../../example_features"))
5
7
  feature_cache = Determinator::Cache::FetchWrapper.new(
6
8
  ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
7
9
  )
@@ -1,3 +1,2 @@
1
1
  ActiveSupport.to_time_preserves_timezone = true
2
- ActiveSupport.halt_callback_chains_on_return_false = false
3
2
  Rails.application.config.ssl_options = { hsts: { subdomains: true } }
@@ -0,0 +1,14 @@
1
+ {
2
+ "id": "colloquial_welcome",
3
+ "identifier": "colloquial_welcome",
4
+ "name": "Whether a colloquial welcome should be used",
5
+ "active": true,
6
+ "bucket_type": "guid",
7
+ "target_groups": [
8
+ {
9
+ "name": "50% of users",
10
+ "rollout": 32768,
11
+ "constraints": {}
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "id": "welcome_emoji",
3
+ "identifier": "welcome_emoji",
4
+ "name": "What emoji should be used for the example hello",
5
+ "active": true,
6
+ "bucket_type": "guid",
7
+ "variants": {
8
+ "👋": 1,
9
+ "🎉": 1
10
+ },
11
+ "winning_variant": null,
12
+ "target_groups": [
13
+ {
14
+ "name": "50% of users",
15
+ "rollout": 32768,
16
+ "constraints": {}
17
+ }
18
+ ]
19
+ }
data/lib/determinator.rb CHANGED
@@ -15,13 +15,13 @@ module Determinator
15
15
  class << self
16
16
  attr_reader :feature_cache, :retrieval
17
17
  # @param :retrieval [Determinator::Retrieve::Routemaster] A retrieval instance for Features
18
+ # @param :feature_cache [#call] a caching proc, accepting a feature name, which will return the named feature or yield (and store) if not available
18
19
  # @param :errors [#call, nil] a proc, accepting an error, which will be called with any errors which occur while determinating
19
20
  # @param :missing_feature [#call, nil] a proc, accepting a feature name, which will be called any time a feature is requested but isn't available
20
- # @param :feature_cache [#call, nil] a caching proc, accepting a feature name, which will return the named feature or yield (and store) if not available
21
- def configure(retrieval:, errors: nil, missing_feature: nil, feature_cache: nil)
21
+ def configure(retrieval:, feature_cache:, errors: nil, missing_feature: nil)
22
22
  self.on_error(&errors) if errors
23
23
  self.on_missing_feature(&missing_feature) if missing_feature
24
- @feature_cache = feature_cache if feature_cache.respond_to?(:call)
24
+ @feature_cache = feature_cache
25
25
  @retrieval = retrieval
26
26
  @instance = Control.new(retrieval: retrieval)
27
27
  end
@@ -30,10 +30,11 @@ module Determinator
30
30
  # @param :id [#to_s] The id of the actor being determinated for
31
31
  # @param :guid [#to_s] The Anonymous id of the actor being determinated for
32
32
  # @param :properties [Hash<Symbol,String>] The properties of this actor which will be used for including this actor or not
33
+ # @param :feature [Feature] The feature to use instead of retrieving one
33
34
  # @raise [ArgumentError] When the arguments given to this method aren't ever going to produce a useful response
34
35
  # @return [true,false] Whether the feature is on (true) or off (false) for this actor
35
- def feature_flag_on?(name, id: nil, guid: nil, properties: {})
36
- determinate_and_notice(name, id: id, guid: guid, properties: properties) do |feature|
36
+ def feature_flag_on?(name, id: nil, guid: nil, properties: {}, feature: nil)
37
+ determinate_and_notice(name, id: id, guid: guid, properties: properties, feature: feature) do |feature|
37
38
  feature.feature_flag?
38
39
  end
39
40
  end
@@ -44,10 +45,11 @@ module Determinator
44
45
  # @param :id [#to_s] The id of the actor being determinated for
45
46
  # @param :guid [#to_s] The Anonymous id of the actor being determinated for
46
47
  # @param :properties [Hash<Symbol,String>] The properties of this actor which will be used for including this actor or not
48
+ # @param :feature [Feature] The feature to use instead of retrieving one
47
49
  # @raise [ArgumentError] When the arguments given to this method aren't ever going to produce a useful response
48
50
  # @return [false,String] Returns false, if the actor is not in this experiment, or otherwise the variant name.
49
- def which_variant(name, id: nil, guid: nil, properties: {})
50
- determinate_and_notice(name, id: id, guid: guid, properties: properties) do |feature|
51
+ def which_variant(name, id: nil, guid: nil, properties: {}, feature: nil)
52
+ determinate_and_notice(name, id: id, guid: guid, properties: properties, feature: feature) do |feature|
51
53
  feature.experiment?
52
54
  end
53
55
  end
@@ -58,6 +60,14 @@ module Determinator
58
60
  end
59
61
  end
60
62
 
63
+ # Uses the retrieval (and a cache if set on the Determinator config) to fetch a feature definition.
64
+ #
65
+ # @param name [#to_s] The name of the experiment being checked
66
+ # @return [Feature, MissingResponse] Returns the Feature object, or MissingResponse if the feature is not found.
67
+ def retrieve(name)
68
+ Determinator.with_retrieval_cache(name) { retrieval.retrieve(name) }
69
+ end
70
+
61
71
  def inspect
62
72
  '#<Determinator::Control>'
63
73
  end
@@ -66,8 +76,8 @@ module Determinator
66
76
 
67
77
  Indicators = Struct.new(:rollout, :variant)
68
78
 
69
- def determinate_and_notice(name, id:, guid:, properties:)
70
- feature = Determinator.with_retrieval_cache(name) { retrieval.retrieve(name) }
79
+ def determinate_and_notice(name, id:, guid:, properties:, feature: nil)
80
+ feature ||= retrieve(name)
71
81
 
72
82
  if feature.nil? || feature.is_a?(ErrorResponse) || feature.is_a?(MissingResponse)
73
83
  Determinator.notice_missing_feature(name)
@@ -164,6 +174,8 @@ module Determinator
164
174
  end
165
175
 
166
176
  def choose_fixed_determination(feature, properties)
177
+ return unless feature.fixed_determinations
178
+
167
179
  # Keys and values must be strings
168
180
  normalised_properties = normalise_properties(properties)
169
181
 
@@ -207,6 +219,9 @@ module Determinator
207
219
  end
208
220
 
209
221
  def matches_constraints(normalised_properties, constraints)
222
+ unless constraints.all?{ |k, v| k.is_a?(String) && v.all?{ |vv| vv.is_a?(String) } }
223
+ raise "Constraints must by arrays of strings"
224
+ end
210
225
  constraints.reduce(true) do |fit, (scope, *required)|
211
226
  present = [*normalised_properties[scope]]
212
227
  fit && matches_requirements?(scope, required, present)
@@ -216,6 +231,7 @@ module Determinator
216
231
  def matches_requirements?(scope, required, present)
217
232
  case scope
218
233
  when "app_version" then has_any_app_version?(required, present)
234
+ when "request.app_version" then has_any_app_version?(required, present)
219
235
  else has_any?(required, present)
220
236
  end
221
237
  end
@@ -3,9 +3,9 @@ module Determinator
3
3
  #
4
4
  # @attr_reader [nil,Hash<String,Integer>] variants The variants for this experiment, with the name of the variant as the key and the weight as the value. Will be nil for non-experiments.
5
5
  class Feature
6
- attr_reader :name, :identifier, :bucket_type, :variants, :target_groups, :fixed_determinations, :active, :winning_variant
6
+ attr_reader :name, :identifier, :bucket_type, :structured_bucket, :variants, :target_groups, :fixed_determinations, :active, :winning_variant
7
7
 
8
- def initialize(name:, identifier:, bucket_type:, target_groups:, fixed_determinations: [], variants: {}, overrides: {}, active: false, winning_variant: nil)
8
+ def initialize(name:, identifier:, bucket_type:, target_groups:, structured_bucket: nil, fixed_determinations: [], variants: {}, overrides: {}, active: false, winning_variant: nil)
9
9
  @name = name.to_s
10
10
  @identifier = identifier.to_s
11
11
  @variants = variants
@@ -14,6 +14,7 @@ module Determinator
14
14
  @winning_variant = parse_outcome(winning_variant, allow_exclusion: false)
15
15
  @active = active
16
16
  @bucket_type = bucket_type.to_sym
17
+ @structured_bucket = structured_bucket
17
18
 
18
19
  # To prevent confusion between actor id data types
19
20
  @overrides = overrides.each_with_object({}) do |(identifier, outcome), hash|
@@ -36,6 +37,11 @@ module Determinator
36
37
  variants.empty?
37
38
  end
38
39
 
40
+ # @return [true,false] Is this feature using structured identification?
41
+ def structured?
42
+ !!structured_bucket && !structured_bucket.empty?
43
+ end
44
+
39
45
  # Is this feature overridden for the given actor id?
40
46
  #
41
47
  # @return [true,false] Whether this feature is overridden for this actor
@@ -78,7 +84,7 @@ module Determinator
78
84
  TargetGroup.new(
79
85
  name: target_group['name'],
80
86
  rollout: target_group['rollout'].to_i,
81
- constraints: parse_constraints(constraints)
87
+ constraints: constraints
82
88
  )
83
89
 
84
90
  # Invalid target groups are ignored
@@ -105,17 +111,11 @@ module Determinator
105
111
  name: fixed_determination['name'],
106
112
  feature_on: fixed_determination['feature_on'],
107
113
  variant: variant,
108
- constraints: parse_constraints(constraints)
114
+ constraints: constraints
109
115
  )
110
116
  # Invalid fixed determinations are ignored
111
117
  rescue
112
118
  nil
113
119
  end
114
-
115
- def parse_constraints(constraints)
116
- constraints.each_with_object({}) do |(key, value), hash|
117
- hash[key.to_s] = [*value].map(&:to_s)
118
- end
119
- end
120
120
  end
121
121
  end
@@ -15,6 +15,7 @@ module Determinator
15
15
  name: obj['name'],
16
16
  identifier: obj['identifier'],
17
17
  bucket_type: obj['bucket_type'],
18
+ structured_bucket: obj['structured_bucket'],
18
19
  active: (obj['active'] === true),
19
20
  target_groups: obj['target_groups'],
20
21
  fixed_determinations: obj['fixed_determinations'].to_a,
@@ -1,3 +1,3 @@
1
1
  module Determinator
2
- VERSION = '2.5.1'
2
+ VERSION = '2.7.0'
3
3
  end
@@ -3,6 +3,9 @@ require_relative '../determinator/retrieve/in_memory_retriever'
3
3
 
4
4
  module RSpec
5
5
  module Determinator
6
+
7
+ DO_NOT_USE_IN_PRODUCTION_CODE_NULL_FEATURE_CACHE = -> (name, &block) { block.call(name) }
8
+
6
9
  def self.included(by)
7
10
  by.extend(DSL)
8
11
 
@@ -12,10 +15,10 @@ module RSpec
12
15
  old_retriever = ::Determinator.instance.retrieval
13
16
  begin
14
17
  fake_retriever.clear!
15
- ::Determinator.configure(retrieval: fake_retriever)
18
+ ::Determinator.configure(retrieval: fake_retriever, feature_cache: DO_NOT_USE_IN_PRODUCTION_CODE_NULL_FEATURE_CACHE)
16
19
  example.run
17
20
  ensure
18
- ::Determinator.configure(retrieval: old_retriever)
21
+ ::Determinator.configure(retrieval: old_retriever, feature_cache: DO_NOT_USE_IN_PRODUCTION_CODE_NULL_FEATURE_CACHE)
19
22
  end
20
23
  end
21
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: determinator
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.1
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Hastings-Spital
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-11 00:00:00.000000000 Z
11
+ date: 2021-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -42,30 +42,30 @@ dependencies:
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 2.1.4
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 2.1.4
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '12.0'
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: '10.0'
68
+ version: '12.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '4.7'
111
111
  - !ruby/object:Gem::Dependency
112
- name: factory_girl
112
+ name: factory_bot
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
@@ -150,7 +150,7 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
- description:
153
+ description:
154
154
  email:
155
155
  - jp@deliveroo.co.uk
156
156
  executables: []
@@ -159,6 +159,7 @@ extra_rdoc_files: []
159
159
  files:
160
160
  - ".circleci/config.yml"
161
161
  - ".circleci/config.yml.erb"
162
+ - ".github/workflows/gem-push.yml"
162
163
  - ".gitignore"
163
164
  - ".gitmodules"
164
165
  - ".rspec"
@@ -175,7 +176,6 @@ files:
175
176
  - docs/background.md
176
177
  - docs/img/determinator.jpg
177
178
  - docs/local_development.md
178
- - examples/determinator-rails/.env
179
179
  - examples/determinator-rails/.gitignore
180
180
  - examples/determinator-rails/Gemfile
181
181
  - examples/determinator-rails/Gemfile.lock
@@ -202,6 +202,8 @@ files:
202
202
  - examples/determinator-rails/config/puma.rb
203
203
  - examples/determinator-rails/config/routes.rb
204
204
  - examples/determinator-rails/config/secrets.yml
205
+ - examples/determinator-rails/example_features/colloquial_welcome
206
+ - examples/determinator-rails/example_features/welcome_emoji
205
207
  - examples/determinator-rails/public/favicon.ico
206
208
  - examples/determinator-rails/public/robots.txt
207
209
  - lib/determinator.rb
@@ -234,7 +236,7 @@ homepage: https://github.com/deliveroo/determinator
234
236
  licenses:
235
237
  - MIT
236
238
  metadata: {}
237
- post_install_message:
239
+ post_install_message:
238
240
  rdoc_options: []
239
241
  require_paths:
240
242
  - lib
@@ -249,8 +251,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
249
251
  - !ruby/object:Gem::Version
250
252
  version: '0'
251
253
  requirements: []
252
- rubygems_version: 3.0.6
253
- signing_key:
254
+ rubygems_version: 3.0.3
255
+ signing_key:
254
256
  specification_version: 4
255
257
  summary: Determine which experiments and features a specific actor should see.
256
258
  test_files: []
@@ -1,7 +0,0 @@
1
- ROUTEMASTER_DRAIN_TOKENS=demo
2
- ROUTEMASTER_DRAIN_REDIS=redis://localhost/0/routemaster/drain
3
- ROUTEMASTER_CACHE_REDIS=redis://localhost/0/routemaster/cache
4
- ROUTEMASTER_CACHE_AUTH=
5
- ROUTEMASTER_QUEUE_ADAPTER=sidekiq
6
- ROUTEMASTER_QUEUE_NAME=routemaster
7
- ROUTEMASTER_CALLBACK_URL=https://determinator-example.dev/events