flipper 0.10.2 → 0.11.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.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
         
     |