flipper 0.10.2 → 0.11.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +42 -0
- data/.rubocop_todo.yml +188 -0
- data/Changelog.md +10 -0
- data/Gemfile +6 -3
- data/README.md +4 -3
- data/Rakefile +13 -13
- data/docs/Adapters.md +2 -1
- data/docs/DockerCompose.md +6 -3
- data/docs/Gates.md +25 -3
- data/docs/Optimization.md +27 -5
- data/docs/api/README.md +73 -32
- data/docs/http/README.md +34 -0
- data/docs/read-only/README.md +22 -0
- data/examples/percentage_of_actors_group.rb +49 -0
- data/flipper.gemspec +15 -15
- data/lib/flipper.rb +2 -5
- data/lib/flipper/adapter.rb +10 -0
- data/lib/flipper/adapters/http.rb +147 -0
- data/lib/flipper/adapters/http/client.rb +83 -0
- data/lib/flipper/adapters/http/error.rb +14 -0
- data/lib/flipper/adapters/instrumented.rb +36 -36
- data/lib/flipper/adapters/memoizable.rb +2 -6
- data/lib/flipper/adapters/memory.rb +10 -9
- data/lib/flipper/adapters/operation_logger.rb +1 -1
- data/lib/flipper/adapters/pstore.rb +12 -11
- data/lib/flipper/adapters/read_only.rb +6 -6
- data/lib/flipper/dsl.rb +1 -3
- data/lib/flipper/feature.rb +11 -16
- data/lib/flipper/gate.rb +3 -3
- data/lib/flipper/gate_values.rb +6 -6
- data/lib/flipper/gates/group.rb +2 -2
- data/lib/flipper/gates/percentage_of_actors.rb +2 -2
- data/lib/flipper/instrumentation/log_subscriber.rb +2 -4
- data/lib/flipper/instrumentation/metriks.rb +1 -1
- data/lib/flipper/instrumentation/statsd.rb +1 -1
- data/lib/flipper/instrumentation/statsd_subscriber.rb +1 -3
- data/lib/flipper/instrumentation/subscriber.rb +11 -10
- data/lib/flipper/instrumenters/memory.rb +1 -5
- data/lib/flipper/instrumenters/noop.rb +1 -1
- data/lib/flipper/middleware/memoizer.rb +11 -27
- data/lib/flipper/middleware/setup_env.rb +44 -0
- data/lib/flipper/registry.rb +8 -10
- data/lib/flipper/spec/shared_adapter_specs.rb +45 -67
- data/lib/flipper/test/shared_adapter_test.rb +25 -31
- data/lib/flipper/typecast.rb +2 -2
- data/lib/flipper/types/actor.rb +2 -4
- data/lib/flipper/types/group.rb +1 -1
- data/lib/flipper/types/percentage.rb +2 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/fixtures/feature.json +31 -0
- data/spec/flipper/adapters/http_spec.rb +148 -0
- data/spec/flipper/adapters/instrumented_spec.rb +20 -20
- data/spec/flipper/adapters/memoizable_spec.rb +59 -59
- data/spec/flipper/adapters/operation_logger_spec.rb +16 -16
- data/spec/flipper/adapters/pstore_spec.rb +6 -6
- data/spec/flipper/adapters/read_only_spec.rb +28 -34
- data/spec/flipper/dsl_spec.rb +73 -84
- data/spec/flipper/feature_check_context_spec.rb +27 -27
- data/spec/flipper/feature_spec.rb +186 -196
- data/spec/flipper/gate_spec.rb +11 -11
- data/spec/flipper/gate_values_spec.rb +46 -45
- data/spec/flipper/gates/actor_spec.rb +2 -2
- data/spec/flipper/gates/boolean_spec.rb +24 -23
- data/spec/flipper/gates/group_spec.rb +19 -19
- data/spec/flipper/gates/percentage_of_actors_spec.rb +10 -10
- data/spec/flipper/gates/percentage_of_time_spec.rb +2 -2
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +20 -20
- data/spec/flipper/instrumentation/metriks_subscriber_spec.rb +20 -20
- data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +11 -11
- data/spec/flipper/instrumenters/memory_spec.rb +5 -5
- data/spec/flipper/instrumenters/noop_spec.rb +6 -6
- data/spec/flipper/middleware/memoizer_spec.rb +83 -100
- data/spec/flipper/middleware/setup_env_spec.rb +76 -0
- data/spec/flipper/registry_spec.rb +35 -39
- data/spec/flipper/typecast_spec.rb +18 -18
- data/spec/flipper/types/actor_spec.rb +30 -29
- data/spec/flipper/types/boolean_spec.rb +8 -8
- data/spec/flipper/types/group_spec.rb +28 -28
- data/spec/flipper/types/percentage_spec.rb +14 -14
- data/spec/flipper_spec.rb +61 -54
- data/spec/helper.rb +26 -21
- data/spec/integration_spec.rb +121 -113
- data/spec/support/fake_udp_socket.rb +1 -1
- data/spec/support/spec_helpers.rb +32 -4
- data/test/adapters/pstore_test.rb +3 -3
- data/test/test_helper.rb +1 -1
- metadata +20 -5
data/docs/api/README.md
CHANGED
@@ -23,26 +23,47 @@ Or install it yourself as:
|
|
23
23
|
```ruby
|
24
24
|
# config/routes.rb
|
25
25
|
YourRailsApp::Application.routes.draw do
|
26
|
-
mount Flipper::Api.app(flipper) => '/flipper
|
26
|
+
mount Flipper::Api.app(flipper) => '/flipper/api'
|
27
27
|
end
|
28
28
|
```
|
29
29
|
|
30
|
+
### Mount Priority - important if using Flipper::UI
|
31
|
+
|
32
|
+
There can be more than one router in your application. Make sure if you choose a path that begins with the same pattern as where Flipper::UI is mounted that the app with the longer pattern is mounted first.
|
33
|
+
|
34
|
+
*bad:*
|
35
|
+
```ruby
|
36
|
+
YourRailsApp::Application.routes.draw do
|
37
|
+
mount Flipper::UI.app(flipper) => '/flipper'
|
38
|
+
mount Flipper::Api.app(flipper) => '/flipper/api'
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
In this case any requests to /flipper\* will be routed to Flipper::UI - including /flipper/api* requests. Simply swap these two to make sure that any requests that don't match /flipper/api\* will be routed to Flipper::UI.
|
43
|
+
|
44
|
+
*good:*
|
45
|
+
```ruby
|
46
|
+
YourRailsApp::Application.routes.draw do
|
47
|
+
mount Flipper::Api.app(flipper) => '/flipper/api'
|
48
|
+
mount Flipper::UI.app(flipper) => '/flipper'
|
49
|
+
end
|
50
|
+
````
|
30
51
|
For more advanced mounting techniques and for suggestions on how to mount in a non-Rails application, it is recommend that you review the [`Flipper::UI` usage documentation](https://github.com/jnunemaker/flipper/blob/master/docs/ui/README.md#usage) as the same approaches apply to `Flipper::Api`.
|
31
52
|
|
32
53
|
## Endpoints
|
33
54
|
|
34
|
-
**Note:** Example CURL requests below assume a mount point of `/flipper
|
55
|
+
**Note:** Example CURL requests below assume a mount point of `/flipper/api`.
|
35
56
|
|
36
57
|
### Get all features
|
37
58
|
|
38
59
|
**URL**
|
39
60
|
|
40
|
-
`GET /
|
61
|
+
`GET /features`
|
41
62
|
|
42
63
|
**Request**
|
43
64
|
|
44
65
|
```
|
45
|
-
curl http://example.com/flipper
|
66
|
+
curl http://example.com/flipper/api/features
|
46
67
|
```
|
47
68
|
|
48
69
|
**Response**
|
@@ -122,7 +143,7 @@ Returns an array of feature objects:
|
|
122
143
|
|
123
144
|
**URL**
|
124
145
|
|
125
|
-
`POST /
|
146
|
+
`POST /features`
|
126
147
|
|
127
148
|
**Parameters**
|
128
149
|
|
@@ -131,7 +152,7 @@ Returns an array of feature objects:
|
|
131
152
|
**Request**
|
132
153
|
|
133
154
|
```
|
134
|
-
curl -X POST -d "name=reports" http://example.com/flipper
|
155
|
+
curl -X POST -d "name=reports" http://example.com/flipper/api/features
|
135
156
|
```
|
136
157
|
|
137
158
|
**Response**
|
@@ -142,7 +163,7 @@ On successful creation, the API will respond with an empty JSON response.
|
|
142
163
|
|
143
164
|
**URL**
|
144
165
|
|
145
|
-
`GET /
|
166
|
+
`GET /features/{feature_name}`
|
146
167
|
|
147
168
|
**Parameters**
|
148
169
|
|
@@ -151,7 +172,7 @@ On successful creation, the API will respond with an empty JSON response.
|
|
151
172
|
**Request**
|
152
173
|
|
153
174
|
```
|
154
|
-
curl http://example.com/flipper
|
175
|
+
curl http://example.com/flipper/api/features/reports
|
155
176
|
```
|
156
177
|
|
157
178
|
**Response**
|
@@ -196,7 +217,7 @@ Returns an individual feature object:
|
|
196
217
|
|
197
218
|
**URL**
|
198
219
|
|
199
|
-
`DELETE /
|
220
|
+
`DELETE /features/{feature_name}`
|
200
221
|
|
201
222
|
**Parameters**
|
202
223
|
|
@@ -205,24 +226,44 @@ Returns an individual feature object:
|
|
205
226
|
**Request**
|
206
227
|
|
207
228
|
```
|
208
|
-
curl -X DELETE http://example.com/flipper
|
229
|
+
curl -X DELETE http://example.com/flipper/api/features/reports
|
209
230
|
```
|
210
231
|
|
211
232
|
**Response**
|
212
233
|
|
213
234
|
Successful deletion of a feature will return a 204 No Content response.
|
214
235
|
|
236
|
+
### Clear a feature
|
237
|
+
|
238
|
+
**URL**
|
239
|
+
|
240
|
+
`DELETE /features/{feature_name}/clear`
|
241
|
+
|
242
|
+
**Parameters**
|
243
|
+
|
244
|
+
* `feature_name` - The name of the feature to clear
|
245
|
+
|
246
|
+
**Request**
|
247
|
+
|
248
|
+
```
|
249
|
+
curl -X DELETE http://example.com/flipper/api/features/reports/clear
|
250
|
+
```
|
251
|
+
|
252
|
+
**Response**
|
253
|
+
|
254
|
+
Successful clearing (removing of all gate values) of a feature will return a 204 No Content response.
|
255
|
+
|
215
256
|
## Gates
|
216
257
|
|
217
258
|
The API supports enabling / disabling any of the Flipper [gates](https://github.com/jnunemaker/flipper/blob/master/docs/Gates.md). Gate endpoints follow the url convention:
|
218
259
|
|
219
260
|
**enable**
|
220
261
|
|
221
|
-
`POST /
|
262
|
+
`POST /{feature_name}/{gate_name}`
|
222
263
|
|
223
264
|
**disable**
|
224
265
|
|
225
|
-
`DELETE /
|
266
|
+
`DELETE /{feature_name}/{gate_name}`
|
226
267
|
|
227
268
|
and on a succesful request return a 200 HTTP status and the feature object as the response body.
|
228
269
|
|
@@ -230,7 +271,7 @@ and on a succesful request return a 200 HTTP status and the feature object as th
|
|
230
271
|
|
231
272
|
**URL**
|
232
273
|
|
233
|
-
`POST /
|
274
|
+
`POST /features/{feature_name}/boolean`
|
234
275
|
|
235
276
|
**Parameters**
|
236
277
|
|
@@ -239,7 +280,7 @@ and on a succesful request return a 200 HTTP status and the feature object as th
|
|
239
280
|
**Request**
|
240
281
|
|
241
282
|
```
|
242
|
-
curl -X POST http://example.com/flipper
|
283
|
+
curl -X POST http://example.com/flipper/api/features/reports/boolean
|
243
284
|
```
|
244
285
|
|
245
286
|
**Response**
|
@@ -285,7 +326,7 @@ Successful enabling of the boolean gate will return a 200 HTTP status and the fe
|
|
285
326
|
|
286
327
|
**URL**
|
287
328
|
|
288
|
-
`DELETE /
|
329
|
+
`DELETE /features/{feature_name}/boolean`
|
289
330
|
|
290
331
|
**Parameters**
|
291
332
|
|
@@ -294,7 +335,7 @@ Successful enabling of the boolean gate will return a 200 HTTP status and the fe
|
|
294
335
|
**Request**
|
295
336
|
|
296
337
|
```
|
297
|
-
curl -X DELETE http://example.com/flipper
|
338
|
+
curl -X DELETE http://example.com/flipper/api/features/reports/boolean
|
298
339
|
```
|
299
340
|
|
300
341
|
**Response**
|
@@ -339,7 +380,7 @@ Successful disabling of the boolean gate will return a 200 HTTP status and the f
|
|
339
380
|
|
340
381
|
**URL**
|
341
382
|
|
342
|
-
`POST /
|
383
|
+
`POST /features/{feature_name}/groups`
|
343
384
|
|
344
385
|
**Parameters**
|
345
386
|
|
@@ -350,7 +391,7 @@ Successful disabling of the boolean gate will return a 200 HTTP status and the f
|
|
350
391
|
**Request**
|
351
392
|
|
352
393
|
```
|
353
|
-
curl -X POST -d "name=admins" http://example.com/flipper
|
394
|
+
curl -X POST -d "name=admins" http://example.com/flipper/api/features/reports/groups
|
354
395
|
```
|
355
396
|
|
356
397
|
**Response**
|
@@ -395,7 +436,7 @@ Successful enabling of the group will return a 200 HTTP status and the feature o
|
|
395
436
|
|
396
437
|
**URL**
|
397
438
|
|
398
|
-
`DELETE /
|
439
|
+
`DELETE /features/{feature_name}/groups`
|
399
440
|
|
400
441
|
**Parameters**
|
401
442
|
|
@@ -406,7 +447,7 @@ Successful enabling of the group will return a 200 HTTP status and the feature o
|
|
406
447
|
**Request**
|
407
448
|
|
408
449
|
```
|
409
|
-
curl -X DELETE -d "name=admins" http://example.com/flipper
|
450
|
+
curl -X DELETE -d "name=admins" http://example.com/flipper/api/features/reports/groups
|
410
451
|
```
|
411
452
|
|
412
453
|
**Response**
|
@@ -450,7 +491,7 @@ Successful disabling of the group will return a 200 HTTP status and the feature
|
|
450
491
|
|
451
492
|
**URL**
|
452
493
|
|
453
|
-
`POST /
|
494
|
+
`POST /features/{feature_name}/actors`
|
454
495
|
|
455
496
|
**Parameters**
|
456
497
|
|
@@ -461,7 +502,7 @@ Successful disabling of the group will return a 200 HTTP status and the feature
|
|
461
502
|
**Request**
|
462
503
|
|
463
504
|
```
|
464
|
-
curl -X POST -d "flipper_id=User:1" http://example.com/flipper
|
505
|
+
curl -X POST -d "flipper_id=User:1" http://example.com/flipper/api/features/reports/actors
|
465
506
|
```
|
466
507
|
|
467
508
|
**Response**
|
@@ -505,7 +546,7 @@ Successful enabling of the actor will return a 200 HTTP status and the feature o
|
|
505
546
|
|
506
547
|
**URL**
|
507
548
|
|
508
|
-
`DELETE /
|
549
|
+
`DELETE /features/{feature_name}/actors`
|
509
550
|
|
510
551
|
**Parameters**
|
511
552
|
|
@@ -516,7 +557,7 @@ Successful enabling of the actor will return a 200 HTTP status and the feature o
|
|
516
557
|
**Request**
|
517
558
|
|
518
559
|
```
|
519
|
-
curl -X DELETE -d "flipper_id=User:1" http://example.com/flipper
|
560
|
+
curl -X DELETE -d "flipper_id=User:1" http://example.com/flipper/api/features/reports/actors
|
520
561
|
```
|
521
562
|
|
522
563
|
**Response**
|
@@ -561,7 +602,7 @@ Successful disabling of the actor will return a 200 HTTP status and the feature
|
|
561
602
|
|
562
603
|
**URL**
|
563
604
|
|
564
|
-
`POST /
|
605
|
+
`POST /features/{feature_name}/percentage_of_actors`
|
565
606
|
|
566
607
|
**Parameters**
|
567
608
|
|
@@ -572,7 +613,7 @@ Successful disabling of the actor will return a 200 HTTP status and the feature
|
|
572
613
|
**Request**
|
573
614
|
|
574
615
|
```
|
575
|
-
curl -X POST -d "percentage=20" http://example.com/flipper
|
616
|
+
curl -X POST -d "percentage=20" http://example.com/flipper/api/features/reports/percentage_of_actors
|
576
617
|
```
|
577
618
|
|
578
619
|
**Response**
|
@@ -616,7 +657,7 @@ Successful enabling of a percentage of actors will return a 200 HTTP status and
|
|
616
657
|
|
617
658
|
**URL**
|
618
659
|
|
619
|
-
`DELETE /
|
660
|
+
`DELETE /features/{feature_name}/percentage_of_actors`
|
620
661
|
|
621
662
|
**Parameters**
|
622
663
|
|
@@ -625,7 +666,7 @@ Successful enabling of a percentage of actors will return a 200 HTTP status and
|
|
625
666
|
**Request**
|
626
667
|
|
627
668
|
```
|
628
|
-
curl -X DELETE http://example.com/flipper
|
669
|
+
curl -X DELETE http://example.com/flipper/api/features/reports/percentage_of_actors
|
629
670
|
```
|
630
671
|
|
631
672
|
**Response**
|
@@ -669,7 +710,7 @@ Successful disabling of a percentage of actors will set the percentage to 0 and
|
|
669
710
|
|
670
711
|
**URL**
|
671
712
|
|
672
|
-
`POST /
|
713
|
+
`POST /features/{feature_name}/percentage_of_time`
|
673
714
|
|
674
715
|
**Parameters**
|
675
716
|
|
@@ -680,7 +721,7 @@ Successful disabling of a percentage of actors will set the percentage to 0 and
|
|
680
721
|
**Request**
|
681
722
|
|
682
723
|
```
|
683
|
-
curl -X POST -d "percentage=20" http://example.com/flipper
|
724
|
+
curl -X POST -d "percentage=20" http://example.com/flipper/api/features/reports/percentage_of_time
|
684
725
|
```
|
685
726
|
|
686
727
|
**Response**
|
@@ -724,7 +765,7 @@ Successful enabling of a percentage of time will return a 200 HTTP status and th
|
|
724
765
|
|
725
766
|
**URL**
|
726
767
|
|
727
|
-
`DELETE /
|
768
|
+
`DELETE /features/{feature_name}/percentage_of_time`
|
728
769
|
|
729
770
|
**Parameters**
|
730
771
|
|
@@ -733,7 +774,7 @@ Successful enabling of a percentage of time will return a 200 HTTP status and th
|
|
733
774
|
**Request**
|
734
775
|
|
735
776
|
```
|
736
|
-
curl -X DELETE http://example.com/flipper
|
777
|
+
curl -X DELETE http://example.com/flipper/api/features/reports/percentage_of_time
|
737
778
|
```
|
738
779
|
|
739
780
|
**Response**
|
data/docs/http/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Flipper Http
|
2
|
+
|
3
|
+
HTTP adapter for use with the [Flipper Api](https://github.com/jnunemaker/flipper/blob/master/docs/api/README.md).
|
4
|
+
|
5
|
+
Given you have [mounted](https://github.com/jnunemaker/flipper/blob/master/docs/api/README.md#user-content-usage) the Flipper Api on an application, you can use the HTTP adapter to interact with Flipper just like any other adapter, and internally it will handle all the http requests for you. This means that you can have the application exposing the API store your Flipper data, but interact with it from other Ruby apps.
|
6
|
+
|
7
|
+
Initialize the HTTP adapter with a configuration Hash.
|
8
|
+
```ruby
|
9
|
+
require 'flipper/adapters/http'
|
10
|
+
|
11
|
+
configuration = {
|
12
|
+
uri: URI('http://app.com/mount-point'), # required
|
13
|
+
headers: { 'X-Custom-Header' => 'foo' },
|
14
|
+
basic_auth_username: 'user123',
|
15
|
+
basic_auth_password: 'password123'
|
16
|
+
read_timeout: 75,
|
17
|
+
open_timeout: 70
|
18
|
+
}
|
19
|
+
|
20
|
+
adapter = Flipper::Adapters::Http.new(configuration)
|
21
|
+
flipper = Flipper.new(adapter)
|
22
|
+
```
|
23
|
+
|
24
|
+
**Required keys**:
|
25
|
+
* uri: [URI](https://docs.ruby-lang.org/en/2.3.0/URI.html) object referencing url where [Flipper Api](https://github.com/jnunemaker/flipper/blob/master/docs/api/README.md) is mounted.
|
26
|
+
|
27
|
+
**Optional keys**:
|
28
|
+
*These will affect every request the adapter makes. For example, send basic auth credentials with every request.*
|
29
|
+
|
30
|
+
* headers: HTTP headers.
|
31
|
+
* basic_auth_username: Basic Auth username.
|
32
|
+
* basic_auth_password: Basic Auth password.
|
33
|
+
* read_timeout: [number in seconds](https://docs.ruby-lang.org/en/2.3.0/Net/HTTP.html#attribute-i-read_timeout).
|
34
|
+
* open_timeout: [number in seconds](https://docs.ruby-lang.org/en/2.3.0/Net/HTTP.html#attribute-i-open_timeout).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Flipper read-only
|
2
|
+
|
3
|
+
A [read-only](https://github.com/jnunemaker/flipper/blob/master/lib/flipper/adapters/read_only.rb) adapter for [Flipper](https://github.com/jnunemaker/flipper).
|
4
|
+
|
5
|
+
Use this adapter to wrap another adapter and raise an exception for any writes.
|
6
|
+
|
7
|
+
Any attempted write raises `Flipper::Adapters::ReadOnly::WriteAttempted` with message `'write attempted while in read only mode'`
|
8
|
+
## Usage
|
9
|
+
```ruby
|
10
|
+
# example wrapping memory adapter
|
11
|
+
require 'flipper/adapters/memory'
|
12
|
+
require 'flipper/adapters/read_only'
|
13
|
+
|
14
|
+
memory_adapter = Flipper::Adapters::Memory.new
|
15
|
+
read_only_adapter = Flipper::Adapters::ReadOnly.new(memory_adapter)
|
16
|
+
|
17
|
+
flipper = Flipper.new(read_only_adapter)
|
18
|
+
|
19
|
+
# Enabling a feature
|
20
|
+
> flipper[:dashboard_panel].enable
|
21
|
+
=> Flipper::Adapters::ReadOnly::WriteAttempted: write attempted while in read only mode
|
22
|
+
```
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# This example shows how to setup a group that enables a feature for a
|
2
|
+
# percentage of actors. It could be combined with other logic to enable a
|
3
|
+
# feature for actors in a particular location or on a particular plan, but only
|
4
|
+
# for a percentage of them. The percentage is a constant, but could easily be
|
5
|
+
# plucked from memcached, redis, mysql or whatever.
|
6
|
+
require File.expand_path('../example_setup', __FILE__)
|
7
|
+
require 'flipper'
|
8
|
+
require 'flipper/adapters/memory'
|
9
|
+
|
10
|
+
adapter = Flipper::Adapters::Memory.new
|
11
|
+
flipper = Flipper.new(adapter)
|
12
|
+
stats = flipper[:stats]
|
13
|
+
|
14
|
+
# Some class that represents what will be trying to do something
|
15
|
+
class User
|
16
|
+
attr_reader :id
|
17
|
+
|
18
|
+
def initialize(id)
|
19
|
+
@id = id
|
20
|
+
end
|
21
|
+
|
22
|
+
# Must respond to flipper_id
|
23
|
+
def flipper_id
|
24
|
+
"User:#{@id}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
PERCENTAGE = 50
|
29
|
+
Flipper.register(:experimental) do |actor|
|
30
|
+
if actor.respond_to?(:flipper_id)
|
31
|
+
Zlib.crc32(actor.flipper_id.to_s) % 100 < PERCENTAGE
|
32
|
+
else
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# enable the experimental group
|
38
|
+
flipper[:stats].enable_group :experimental
|
39
|
+
|
40
|
+
# create a bunch of fake users and see how many are enabled
|
41
|
+
total = 10_000
|
42
|
+
users = (1..total).map { |n| User.new(n) }
|
43
|
+
enabled = users.map { |user|
|
44
|
+
flipper[:stats].enabled?(user) ? true : nil
|
45
|
+
}.compact
|
46
|
+
|
47
|
+
# show the results
|
48
|
+
actual = (enabled.size / total.to_f * 100).round
|
49
|
+
puts "percentage: #{actual} vs hoped for: #{PERCENTAGE}"
|
data/flipper.gemspec
CHANGED
@@ -4,34 +4,34 @@ require File.expand_path('../lib/flipper/version', __FILE__)
|
|
4
4
|
plugin_files = []
|
5
5
|
plugin_test_files = []
|
6
6
|
|
7
|
-
Dir['flipper-*.gemspec'].map
|
7
|
+
Dir['flipper-*.gemspec'].map do |gemspec|
|
8
8
|
spec = eval(File.read(gemspec))
|
9
9
|
plugin_files << spec.files
|
10
10
|
plugin_test_files << spec.files
|
11
|
-
|
11
|
+
end
|
12
12
|
|
13
13
|
ignored_files = plugin_files
|
14
14
|
ignored_files << Dir['script/*']
|
15
|
-
ignored_files <<
|
16
|
-
ignored_files <<
|
17
|
-
ignored_files <<
|
15
|
+
ignored_files << '.travis.yml'
|
16
|
+
ignored_files << '.gitignore'
|
17
|
+
ignored_files << 'Guardfile'
|
18
18
|
ignored_files.flatten!.uniq!
|
19
19
|
|
20
20
|
ignored_test_files = plugin_test_files
|
21
21
|
ignored_test_files.flatten!.uniq!
|
22
22
|
|
23
23
|
Gem::Specification.new do |gem|
|
24
|
-
gem.authors = [
|
25
|
-
gem.email = [
|
26
|
-
gem.summary =
|
27
|
-
gem.description =
|
28
|
-
gem.homepage =
|
29
|
-
gem.license =
|
24
|
+
gem.authors = ['John Nunemaker']
|
25
|
+
gem.email = ['nunemaker@gmail.com']
|
26
|
+
gem.summary = 'Feature flipper for ANYTHING'
|
27
|
+
gem.description = 'Feature flipper is the act of enabling/disabling features in your application, ideally without re-deploying or changing anything in your code base. Flipper makes this extremely easy to do with any backend you would like to use.'
|
28
|
+
gem.homepage = 'https://github.com/jnunemaker/flipper'
|
29
|
+
gem.license = 'MIT'
|
30
30
|
|
31
|
-
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
32
|
-
gem.files = `git ls-files`.split("\n") - ignored_files + [
|
31
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
32
|
+
gem.files = `git ls-files`.split("\n") - ignored_files + ['lib/flipper/version.rb']
|
33
33
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - ignored_test_files
|
34
|
-
gem.name =
|
35
|
-
gem.require_paths = [
|
34
|
+
gem.name = 'flipper'
|
35
|
+
gem.require_paths = ['lib']
|
36
36
|
gem.version = Flipper::VERSION
|
37
37
|
end
|