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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +42 -0
  3. data/.rubocop_todo.yml +188 -0
  4. data/Changelog.md +10 -0
  5. data/Gemfile +6 -3
  6. data/README.md +4 -3
  7. data/Rakefile +13 -13
  8. data/docs/Adapters.md +2 -1
  9. data/docs/DockerCompose.md +6 -3
  10. data/docs/Gates.md +25 -3
  11. data/docs/Optimization.md +27 -5
  12. data/docs/api/README.md +73 -32
  13. data/docs/http/README.md +34 -0
  14. data/docs/read-only/README.md +22 -0
  15. data/examples/percentage_of_actors_group.rb +49 -0
  16. data/flipper.gemspec +15 -15
  17. data/lib/flipper.rb +2 -5
  18. data/lib/flipper/adapter.rb +10 -0
  19. data/lib/flipper/adapters/http.rb +147 -0
  20. data/lib/flipper/adapters/http/client.rb +83 -0
  21. data/lib/flipper/adapters/http/error.rb +14 -0
  22. data/lib/flipper/adapters/instrumented.rb +36 -36
  23. data/lib/flipper/adapters/memoizable.rb +2 -6
  24. data/lib/flipper/adapters/memory.rb +10 -9
  25. data/lib/flipper/adapters/operation_logger.rb +1 -1
  26. data/lib/flipper/adapters/pstore.rb +12 -11
  27. data/lib/flipper/adapters/read_only.rb +6 -6
  28. data/lib/flipper/dsl.rb +1 -3
  29. data/lib/flipper/feature.rb +11 -16
  30. data/lib/flipper/gate.rb +3 -3
  31. data/lib/flipper/gate_values.rb +6 -6
  32. data/lib/flipper/gates/group.rb +2 -2
  33. data/lib/flipper/gates/percentage_of_actors.rb +2 -2
  34. data/lib/flipper/instrumentation/log_subscriber.rb +2 -4
  35. data/lib/flipper/instrumentation/metriks.rb +1 -1
  36. data/lib/flipper/instrumentation/statsd.rb +1 -1
  37. data/lib/flipper/instrumentation/statsd_subscriber.rb +1 -3
  38. data/lib/flipper/instrumentation/subscriber.rb +11 -10
  39. data/lib/flipper/instrumenters/memory.rb +1 -5
  40. data/lib/flipper/instrumenters/noop.rb +1 -1
  41. data/lib/flipper/middleware/memoizer.rb +11 -27
  42. data/lib/flipper/middleware/setup_env.rb +44 -0
  43. data/lib/flipper/registry.rb +8 -10
  44. data/lib/flipper/spec/shared_adapter_specs.rb +45 -67
  45. data/lib/flipper/test/shared_adapter_test.rb +25 -31
  46. data/lib/flipper/typecast.rb +2 -2
  47. data/lib/flipper/types/actor.rb +2 -4
  48. data/lib/flipper/types/group.rb +1 -1
  49. data/lib/flipper/types/percentage.rb +2 -1
  50. data/lib/flipper/version.rb +1 -1
  51. data/spec/fixtures/feature.json +31 -0
  52. data/spec/flipper/adapters/http_spec.rb +148 -0
  53. data/spec/flipper/adapters/instrumented_spec.rb +20 -20
  54. data/spec/flipper/adapters/memoizable_spec.rb +59 -59
  55. data/spec/flipper/adapters/operation_logger_spec.rb +16 -16
  56. data/spec/flipper/adapters/pstore_spec.rb +6 -6
  57. data/spec/flipper/adapters/read_only_spec.rb +28 -34
  58. data/spec/flipper/dsl_spec.rb +73 -84
  59. data/spec/flipper/feature_check_context_spec.rb +27 -27
  60. data/spec/flipper/feature_spec.rb +186 -196
  61. data/spec/flipper/gate_spec.rb +11 -11
  62. data/spec/flipper/gate_values_spec.rb +46 -45
  63. data/spec/flipper/gates/actor_spec.rb +2 -2
  64. data/spec/flipper/gates/boolean_spec.rb +24 -23
  65. data/spec/flipper/gates/group_spec.rb +19 -19
  66. data/spec/flipper/gates/percentage_of_actors_spec.rb +10 -10
  67. data/spec/flipper/gates/percentage_of_time_spec.rb +2 -2
  68. data/spec/flipper/instrumentation/log_subscriber_spec.rb +20 -20
  69. data/spec/flipper/instrumentation/metriks_subscriber_spec.rb +20 -20
  70. data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +11 -11
  71. data/spec/flipper/instrumenters/memory_spec.rb +5 -5
  72. data/spec/flipper/instrumenters/noop_spec.rb +6 -6
  73. data/spec/flipper/middleware/memoizer_spec.rb +83 -100
  74. data/spec/flipper/middleware/setup_env_spec.rb +76 -0
  75. data/spec/flipper/registry_spec.rb +35 -39
  76. data/spec/flipper/typecast_spec.rb +18 -18
  77. data/spec/flipper/types/actor_spec.rb +30 -29
  78. data/spec/flipper/types/boolean_spec.rb +8 -8
  79. data/spec/flipper/types/group_spec.rb +28 -28
  80. data/spec/flipper/types/percentage_spec.rb +14 -14
  81. data/spec/flipper_spec.rb +61 -54
  82. data/spec/helper.rb +26 -21
  83. data/spec/integration_spec.rb +121 -113
  84. data/spec/support/fake_udp_socket.rb +1 -1
  85. data/spec/support/spec_helpers.rb +32 -4
  86. data/test/adapters/pstore_test.rb +3 -3
  87. data/test/test_helper.rb +1 -1
  88. metadata +20 -5
@@ -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-api'
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-api`.
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 /api/v1/features`
61
+ `GET /features`
41
62
 
42
63
  **Request**
43
64
 
44
65
  ```
45
- curl http://example.com/flipper-api/api/v1/features
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 /api/v1/features`
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-api/api/v1/features
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 /api/v1/features/{feature_name}`
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-api/api/v1/features/reports
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 /api/v1/features/{feature_name}`
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-api/api/v1/features/reports
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 /api/v1/{feature_name}/{gate_name}`
262
+ `POST /{feature_name}/{gate_name}`
222
263
 
223
264
  **disable**
224
265
 
225
- `DELETE /api/v1/{feature_name}/{gate_name}`
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 /api/v1/features/{feature_name}/boolean`
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-api/api/v1/features/reports/boolean
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 /api/v1/features/{feature_name}/boolean`
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-api/api/v1/features/reports/boolean
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 /api/v1/features/{feature_name}/groups`
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-api/api/v1/features/reports/groups
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 /api/v1/features/{feature_name}/groups`
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-api/api/v1/features/reports/groups
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 /api/v1/features/{feature_name}/actors`
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-api/api/v1/features/reports/actors
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 /api/v1/features/{feature_name}/actors`
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-api/api/v1/features/reports/actors
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 /api/v1/features/{feature_name}/percentage_of_actors`
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-api/api/v1/features/reports/percentage_of_actors
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 /api/v1/features/{feature_name}/percentage_of_actors`
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-api/api/v1/features/reports/percentage_of_actors
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 /api/v1/features/{feature_name}/percentage_of_time`
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-api/api/v1/features/reports/percentage_of_time
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 /api/v1/features/{feature_name}/percentage_of_time`
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-api/api/v1/features/reports/percentage_of_time
777
+ curl -X DELETE http://example.com/flipper/api/features/reports/percentage_of_time
737
778
  ```
738
779
 
739
780
  **Response**
@@ -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}"
@@ -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 { |gemspec|
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 << ".travis.yml"
16
- ignored_files << ".gitignore"
17
- ignored_files << "Guardfile"
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 = ["John Nunemaker"]
25
- gem.email = ["nunemaker@gmail.com"]
26
- gem.summary = %q{Feature flipper for ANYTHING}
27
- gem.description = %q{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"
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 + ["lib/flipper/version.rb"]
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 = "flipper"
35
- gem.require_paths = ["lib"]
34
+ gem.name = 'flipper'
35
+ gem.require_paths = ['lib']
36
36
  gem.version = Flipper::VERSION
37
37
  end