flipper 0.17.1 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +57 -0
  3. data/Changelog.md +114 -1
  4. data/Dockerfile +1 -1
  5. data/Gemfile +3 -6
  6. data/README.md +103 -47
  7. data/Rakefile +1 -4
  8. data/docs/Adapters.md +9 -9
  9. data/docs/Caveats.md +2 -2
  10. data/docs/DockerCompose.md +0 -1
  11. data/docs/Gates.md +74 -74
  12. data/docs/Optimization.md +70 -47
  13. data/docs/http/README.md +12 -11
  14. data/docs/images/banner.jpg +0 -0
  15. data/docs/read-only/README.md +8 -5
  16. data/examples/basic.rb +1 -12
  17. data/examples/configuring_default.rb +2 -5
  18. data/examples/dsl.rb +13 -24
  19. data/examples/enabled_for_actor.rb +8 -15
  20. data/examples/group.rb +3 -6
  21. data/examples/group_dynamic_lookup.rb +5 -19
  22. data/examples/group_with_members.rb +4 -14
  23. data/examples/importing.rb +1 -1
  24. data/examples/individual_actor.rb +2 -5
  25. data/examples/instrumentation.rb +1 -2
  26. data/examples/memoizing.rb +35 -0
  27. data/examples/percentage_of_actors.rb +6 -16
  28. data/examples/percentage_of_actors_enabled_check.rb +7 -10
  29. data/examples/percentage_of_actors_group.rb +5 -18
  30. data/examples/percentage_of_time.rb +3 -6
  31. data/flipper.gemspec +3 -4
  32. data/lib/flipper.rb +7 -3
  33. data/lib/flipper/adapters/dual_write.rb +67 -0
  34. data/lib/flipper/adapters/http.rb +32 -28
  35. data/lib/flipper/adapters/memory.rb +23 -94
  36. data/lib/flipper/adapters/operation_logger.rb +5 -0
  37. data/lib/flipper/adapters/pstore.rb +8 -1
  38. data/lib/flipper/adapters/sync.rb +7 -7
  39. data/lib/flipper/adapters/sync/interval_synchronizer.rb +1 -1
  40. data/lib/flipper/adapters/sync/synchronizer.rb +1 -0
  41. data/lib/flipper/configuration.rb +33 -7
  42. data/lib/flipper/dsl.rb +8 -0
  43. data/lib/flipper/errors.rb +2 -3
  44. data/lib/flipper/feature.rb +2 -2
  45. data/lib/flipper/identifier.rb +17 -0
  46. data/lib/flipper/middleware/memoizer.rb +30 -15
  47. data/lib/flipper/middleware/setup_env.rb +13 -3
  48. data/lib/flipper/railtie.rb +38 -0
  49. data/lib/flipper/spec/shared_adapter_specs.rb +15 -0
  50. data/lib/flipper/test/shared_adapter_test.rb +16 -1
  51. data/lib/flipper/version.rb +1 -1
  52. data/spec/flipper/adapter_spec.rb +2 -2
  53. data/spec/flipper/adapters/dual_write_spec.rb +71 -0
  54. data/spec/flipper/adapters/http_spec.rb +74 -8
  55. data/spec/flipper/adapters/memory_spec.rb +21 -1
  56. data/spec/flipper/adapters/operation_logger_spec.rb +9 -0
  57. data/spec/flipper/adapters/sync_spec.rb +4 -4
  58. data/spec/flipper/configuration_spec.rb +20 -2
  59. data/spec/flipper/feature_spec.rb +5 -5
  60. data/spec/flipper/identifier_spec.rb +14 -0
  61. data/spec/flipper/middleware/memoizer_spec.rb +95 -35
  62. data/spec/flipper/middleware/setup_env_spec.rb +23 -3
  63. data/spec/flipper/railtie_spec.rb +69 -0
  64. data/spec/{integration_spec.rb → flipper_integration_spec.rb} +0 -0
  65. data/spec/flipper_spec.rb +26 -0
  66. data/spec/helper.rb +3 -3
  67. data/spec/support/descriptions.yml +1 -0
  68. data/spec/support/spec_helpers.rb +25 -0
  69. data/test/test_helper.rb +2 -1
  70. metadata +19 -10
  71. data/.rubocop.yml +0 -52
  72. data/.rubocop_todo.yml +0 -562
  73. data/examples/example_setup.rb +0 -8
data/docs/Caveats.md CHANGED
@@ -1,4 +1,4 @@
1
1
  # Caveats
2
2
 
3
- 1. The [individual actor gate](https://github.com/jnunemaker/flipper/blob/master/docs/Gates.md#2-individual-actor) is typically not designed for hundreds or thousands of actors to be enabled. This is an explicit choice to make it easier to batch load data from the adapters instead of performing individual checks for actors over and over. If you need to enable something for more than 20 individual people, I would recommend using a [group](https://github.com/jnunemaker/flipper/blob/master/docs/Gates.md#5-group).
4
- 2. The disable method exists only to clear something that is enabled. If the thing you are disabling is not enabled, the disable is pointless. This means that if you enable one group an actor is in and disable another group, the feature will be enabled for the actor. ([related issue](https://github.com/jnunemaker/flipper/issues/71))
3
+ 1. The [individual actor gate](https://github.com/jnunemaker/flipper/blob/master/docs/Gates.md#2-individual-actor) is typically not designed for hundreds or thousands of actors to be enabled. This is an explicit choice to make it easier to batch load data from the adapters instead of performing individual checks for actors over and over. If you need to enable something for more than 100 individual actors, I would recommend using a [group](https://github.com/jnunemaker/flipper/blob/master/docs/Gates.md#5-group).
4
+ 2. The `disable` method exists only to clear something that is enabled. If the thing you are disabling is not enabled, the disable is pointless. This means that if you enable one group an actor is in and disable another group, the feature will be enabled for the actor. ([related issue](https://github.com/jnunemaker/flipper/issues/71))
@@ -11,7 +11,6 @@ new contributor could start working on code with a minumum efforts.
11
11
  1. Install gems `docker-compose run --rm app bundle install`
12
12
  1. Run specs `docker-compose run --rm app bundle exec rspec`
13
13
  1. Run tests `docker-compose run --rm app bundle exec rake test`
14
- 1. Clear and check files with Rubocop `docker-compose run --rm app bundle exec rubocop -D`
15
14
  1. Optional: log in to container an using a `bash` shell for running specs
16
15
  ```sh
17
16
  docker-compose run --rm app bash
data/docs/Gates.md CHANGED
@@ -7,76 +7,82 @@ Out of the box several types of enabling are supported. They are checked in this
7
7
  All on or all off. Think top level things like `:stats`, `:search`, `:logging`, etc. Also, an easy way to release a new feature as once a feature is boolean enabled it is on for every situation.
8
8
 
9
9
  ```ruby
10
- flipper = Flipper.new(adapter)
11
- flipper[:stats].enable # turn on
12
- flipper[:stats].disable # turn off
13
- flipper[:stats].enabled? # check
10
+ Flipper.enable :stats # turn on
11
+ Flipper.disable :stats # turn off
12
+ Flipper.enabled? :stats # check
14
13
  ```
15
14
 
16
15
  ## 2. Individual Actor
17
16
 
18
- Turn feature on for individual thing. Think enable feature for someone to test or for a buddy. The only requirement for an individual actor is that it must respond to `flipper_id`.
17
+ Turn feature on for individual thing. Think enable feature for someone to test or for a buddy.
19
18
 
20
19
  ```ruby
21
- flipper = Flipper.new(adapter)
20
+ Flipper.enable_actor :stats, user
21
+ Flipper.enabled? :stats, user # true
22
22
 
23
- flipper[:stats].enable user
24
- flipper[:stats].enabled? user # true
25
-
26
- flipper[:stats].disable user
27
- flipper[:stats].enabled? user # false
23
+ Flipper.disable_actor :stats, user
24
+ Flipper.enabled? :stats, user # false
28
25
 
29
26
  # you can enable anything, does not need to be user or person
30
- flipper[:search].enable group
31
- flipper[:search].enabled? group
32
-
33
- # you can also use shortcut methods
34
- flipper.enable_actor :search, user
35
- flipper.disable_actor :search, user
36
- flipper[:search].enable_actor user
37
- flipper[:search].disable_actor user
38
- ```
27
+ Flipper.enable_actor :search, organization
28
+ Flipper.enabled? :search, organization
39
29
 
40
- The key is to make sure you do not enable two different types of objects for the same feature. Imagine that user has a `flipper_id` of 6 and group has a `flipper_id` of 6. Enabling search for user would automatically enable it for group, as they both have a `flipper_id` of 6.
30
+ # you can also save a reference to a specific feature
31
+ feature = Flipper[:search]
32
+
33
+ feature.enable_actor user
34
+ feature.enabled? user # true
35
+ feature.disable_actor user
36
+ ```
41
37
 
42
- The one exception to this rule is if you have globally unique `flipper_ids`, such as UUIDs. If your `flipper_ids` are unique globally in your entire system, enabling two different types should be safe. Another way around this is to prefix the `flipper_id` with the class name like this:
38
+ The only requirement for an individual actor is that it must have a unique `flipper_id`. Include the `Flipper::Identifier` module for a default implementation which combines the class name and `id` (e.g. `User;6`).
43
39
 
44
40
  ```ruby
45
- class User
46
- def flipper_id
47
- "User;#{id}"
48
- end
41
+ class User < Struct.new(:id)
42
+ include Flipper::Identifier
49
43
  end
50
44
 
51
- class Group
45
+ User.new(5).flipper_id # => "User;5"
46
+ ```
47
+
48
+ You can also define your own implementation:
49
+
50
+ ```
51
+ class Organization < Struct.new(:uuid)
52
52
  def flipper_id
53
- "Group;#{id}"
53
+ uuid
54
54
  end
55
55
  end
56
+
57
+ Organization.new("DEB3D850-39FB-444B-A1E9-404A990FDBE0").flipper_id
58
+ # => "DEB3D850-39FB-444B-A1E9-404A990FDBE0"
56
59
  ```
57
60
 
61
+ Just make sure each type of object has a unique `flipper_id`.
62
+
58
63
  ## 3. Percentage of Actors
59
64
 
60
65
  Turn this on for a percentage of actors (think user, member, account, group, whatever). Consistently on or off for this user as long as percentage increases. Think slow rollout of a new feature to a percentage of things.
61
66
 
62
67
  ```ruby
63
- flipper = Flipper.new(adapter)
64
-
65
- # returns a percentage of actors instance set to 10
66
- percentage = flipper.actors(10)
67
-
68
68
  # turn stats on for 10 percent of users in the system
69
- flipper[:stats].enable percentage
69
+ Flipper.enable :stats, Flipper.actors(10)
70
+ # or
71
+ Flipper.enable_percentage_of_actors :stats, 10
70
72
 
71
73
  # checks if actor's flipper_id is in the enabled percentage by hashing
72
74
  # user.flipper_id.to_s to ensure enabled distribution is smooth
73
- flipper[:stats].enabled? user
75
+ Flipper.enabled? :stats, user
74
76
 
75
- # you can also use shortcut methods
76
- flipper.enable_percentage_of_actors :search, 10
77
- flipper.disable_percentage_of_actors :search # sets to 0
78
- flipper[:search].enable_percentage_of_actors 10
79
- flipper[:search].disable_percentage_of_actors # sets to 0
77
+ Flipper.disable_percentage_of_actors :search # sets to 0
78
+ # or
79
+ Flipper.disable :stats, Flipper.actors(0)
80
+
81
+ # you can also save a reference to a specific feature
82
+ feature = Flipper[:search]
83
+ feature.enable_percentage_of_actors 10
84
+ feature.enabled? user
85
+ feature.disable_percentage_of_actors # sets to 0
80
86
  ```
81
87
 
82
88
  ## 4. Percentage of Time
@@ -84,22 +90,20 @@ flipper[:search].disable_percentage_of_actors # sets to 0
84
90
  Turn this on for a percentage of time. Think load testing new features behind the scenes and such.
85
91
 
86
92
  ```ruby
87
- flipper = Flipper.new(adapter)
88
-
89
- # get percentage of time instance set to 5
90
- percentage = flipper.time(5)
91
-
92
93
  # Register a feature called logging and turn it on for 5 percent of the time.
93
94
  # This could be on during one request and off the next
94
95
  # could even be on first time in request and off second time
95
- flipper[:logging].enable percentage
96
- flipper[:logging].enabled? # this will return true 5% of the time.
97
-
98
- # you can also use shortcut methods
99
- flipper.enable_percentage_of_time :search, 5 # registers a feature called "enable_percentage_of_time" and enables it 5% of the time
100
- flipper.disable_percentage_of_time :search # sets to 0
101
- flipper[:search].enable_percentage_of_time 5
102
- flipper[:search].disable_percentage_of_time # sets to 0
96
+ Flipper.enable_percentage_of_time :logging, 5
97
+
98
+ Flipper.enabled? :logging # this will return true 5% of the time.
99
+
100
+ Flipper.disable_percentage_of_time :logging # sets to 0
101
+
102
+ # you can also save a reference to a specific feature
103
+ feature = Flipper[:search]
104
+ feature.enable_percentage_of_time, 5
105
+ feature.enabled?
106
+ feature.disable_percentage_of_time
103
107
  ```
104
108
 
105
109
  Timeness is not a good idea for enabling new features in the UI. Most of the time you want a feature on or off for a user, but there are definitely times when I have found percentage of time to be very useful.
@@ -114,52 +118,48 @@ Flipper.register(:admins) do |actor|
114
118
  actor.respond_to?(:admin?) && actor.admin?
115
119
  end
116
120
 
117
- flipper = Flipper.new(adapter)
118
-
119
- flipper[:stats].enable flipper.group(:admins) # This registers a stats feature and turns it on for admins (which is anything that returns true from the registered block).
120
- flipper[:stats].disable flipper.group(:admins) # turn off the stats feature for admins
121
+ Flipper.enable_group :stats, :admins # This registers a stats feature and turns it on for admins (which is anything that returns true from the registered block).
122
+ Flipper.disable_group :stats, :admins # turn off the stats feature for admins
121
123
 
122
124
  person = Person.find(params[:id])
123
- flipper[:stats].enabled? person # check if enabled, returns true if person.admin? is true
125
+ Flipper.enabled? :stats, person # check if enabled, returns true if person.admin? is true
124
126
 
125
- # you can also use shortcut methods. This also registers a stats feature and turns it on for admins.
126
- flipper.enable_group :stats, :admins
127
- person = Person.find(params[:id])
128
- flipper[:stats].enabled? person # same as above. check if enabled, returns true if person.admin? is true
129
127
 
130
- flipper.disable_group :stats, :admins
131
- flipper[:stats].enable_group :admins
132
- flipper[:stats].disable_group :admins
128
+ # you can also use shortcut methods. This also registers a stats feature and turns it on for admins.
129
+ feature = Flipper[:search]
130
+ feature.enable_group :admins
131
+ feature.enabled? person
132
+ feature.disable_group :admins
133
133
  ```
134
134
 
135
135
  Here's a quick explanation of the above code block:
136
136
 
137
- ```
137
+ ```ruby
138
138
  Flipper.register(:admins) do |actor|
139
139
  actor.respond_to?(:admin?) && actor.admin?
140
140
  end
141
141
  ```
142
- - The above first registers a group called `admins` which essentially saves a [Proc](http://www.eriktrautman.com/posts/ruby-explained-blocks-procs-and-lambdas-aka-closures) to be called later.
142
+ - The above first registers a group called `admins` which essentially saves a [Proc](http://www.eriktrautman.com/posts/ruby-explained-blocks-procs-and-lambdas-aka-closures) to be called later. The `actor` is an instance of the `Flipper::Types::Actor` that wraps the thing being checked against and `actor.thing` is the original object being checked.
143
143
 
144
- ```
145
- flipper[:stats].enable flipper.group(:admins)
144
+ ```ruby
145
+ Flipper.enable_group :stats, :admins
146
146
  ```
147
147
 
148
148
  - The above enables the stats feature to any object that returns true from the `:admins` proc.
149
149
 
150
- ```
150
+ ```ruby
151
151
  person = Person.find(params[:id])
152
- flipper[:stats].enabled? person # check if person is enabled, returns true if person.admin? is true
152
+ Flipper.enabled? :stats, person # check if person is enabled, returns true if person.admin? is true
153
153
  ```
154
154
 
155
- When the `person` object is passed to the `enabled?` method, it is then passed into the proc. If the proc returns true, the entire statement returns true and so `flipper[:stats].enabled? person` returns true. Whatever logic follows this conditional check is then executed.
155
+ When the `person` object is passed to the `enabled?` method, it is then passed into the proc. If the proc returns true, the entire statement returns true and so `Flipper[:stats].enabled? person` returns true. Whatever logic follows this conditional check is then executed.
156
156
 
157
157
  There is no requirement that the thing yielded to the block be a user model or whatever. It can be anything you want, therefore it is a good idea to check that the thing passed into the group block actually responds to what you are trying to do in the `register` proc.
158
158
 
159
159
  In your application code, you can do something like this now:
160
160
 
161
- ```
162
- if flipper[:stats].enabled?(some_admin)
161
+ ```ruby
162
+ if Flipper.enabled? :stats, some_admin
163
163
  # do thing...
164
164
  else
165
165
  # do not do thing
data/docs/Optimization.md CHANGED
@@ -1,52 +1,63 @@
1
1
  # Optimization
2
2
 
3
- ## Memoizing Middleware
3
+ ## Memoization
4
4
 
5
- One optimization that flipper provides is a memoizing middleware. The memoizing middleware ensures that you only make one adapter call per feature per request. This means if you check the same feature over and over, it will only make one Mongo, Redis, or whatever call per feature for the length of the request.
5
+ By default, Flipper will preload and memoize all features to ensure one adapter call per request. This means no matter how many times you check features, Flipper will only make one network request to Postgres, MySQL, Redis, Mongo or whatever adapter you are using for the length of the request.
6
6
 
7
- You can use the middleware like so for Rails:
7
+ ### Preloading
8
+
9
+ Flipper will preload all features before each request by default, which is recommended if you have a limited number of features (< 100?) and they are used on most requests. If you have a lot of features, but only a few are used on most requests, you may want to customize preloading:
8
10
 
9
11
  ```ruby
10
- # setup default instance (perhaps in config/initializer/flipper.rb)
11
- Flipper.configure do |config|
12
- config.default do
13
- Flipper.new(...)
14
- end
12
+ # config/initializers/flipper.rb
13
+ Rails.application.configure do
14
+ # Load specific features that are used on most requests
15
+ config.flipper.preload = [:stats, :search, :some_feature]
16
+
17
+ # Or completely disable preloading
18
+ config.flipper.preload = false
15
19
  end
20
+ ```
21
+
22
+ Features that are not preloaded are still memoized, ensuring one adapter call per feature during a request.
23
+
24
+ ### Skip memoization
25
+
26
+ Prevent preloading and memoization on specific requests by setting `memoize` to a proc that evaluates to false.
16
27
 
17
- # This assumes you setup a default flipper instance using configure.
18
- config.middleware.use Flipper::Middleware::Memoizer
28
+ ```ruby
29
+ # config/initializers/flipper.rb
30
+ Rails.application.configure do
31
+ config.flipper.memoize = ->(request) { !request.path.start_with?("/assets") }
32
+ end
19
33
  ```
20
34
 
21
- **Note**: Be sure that the middleware is high enough up in your stack that all feature checks are wrapped.
35
+ ### Disable memoization
22
36
 
23
- **Also Note**: If you haven't setup a default instance, you can pass the instance to `SetupEnv` as `Memoizer` uses whatever is setup in the `env`:
37
+ To disable memoization entirely:
24
38
 
25
39
  ```ruby
26
- config.middleware.use Flipper::Middleware::SetupEnv, -> { Flipper.new(...) }
27
- config.middleware.use Flipper::Middleware::Memoizer
40
+ Rails.application.configure do
41
+ config.flipper.memoize = false
42
+ end
28
43
  ```
29
44
 
30
- ### Options
31
-
32
- The Memoizer middleware also supports a few options. Use either `preload` or `preload_all`, not both.
33
-
34
- * **`:preload`** - An `Array` of feature names (`Symbol`) to preload for every request. Useful if you have features that are used on every endpoint. `preload` uses `Adapter#get_multi` to attempt to load the features in one network call instead of N+1 network calls.
35
- ```ruby
36
- config.middleware.use Flipper::Middleware::Memoizer,
37
- preload: [:stats, :search, :some_feature]
38
- ```
39
- * **`:preload_all`** - A Boolean value (default: false) of whether or not all features should be preloaded. Using this results in a `preload_all` call with the result of `Adapter#get_all`. Any subsequent feature checks will be memoized and perform no network calls. I wouldn't recommend using this unless you have few features (< 100?) and nearly all of them are used on every request.
40
- ```ruby
41
- config.middleware.use Flipper::Middleware::Memoizer,
42
- preload_all: true
43
- ```
44
- * **`:unless`** - A block that prevents preloading and memoization if it evaluates to true.
45
- ```ruby
46
- # skip preloading and memoizing if path starts with /assets
47
- config.middleware.use Flipper::Middleware::Memoizer,
48
- unless: ->(request) { request.path.start_with?("/assets") }
49
- ```
45
+ ### Advanced
46
+
47
+ Memoization is implemented as a Rack middleware, which can be used manually in any Ruby app:
48
+
49
+ ```ruby
50
+ use Flipper::Middleware::Memoizer,
51
+ preload: true,
52
+ unless: ->(request) { request.path.start_with?("/assets") }
53
+ ```
54
+
55
+ **Also Note**: If you need to customize the instance of Flipper used by the memoizer, you can pass the instance to `SetupEnv`:
56
+
57
+ ```ruby
58
+ use Flipper::Middleware::SetupEnv, -> { Flipper.new(...) }
59
+ use Flipper::Middleware::Memoizer
60
+ ```
50
61
 
51
62
  ## Cache Adapters
52
63
 
@@ -61,11 +72,15 @@ https://github.com/petergoldstein/dalli
61
72
  Example using the Dalli cache adapter with the Memory adapter and a TTL of 600 seconds:
62
73
 
63
74
  ```ruby
64
- dalli_client = Dalli::Client.new('localhost:11211')
65
- memory_adapter = Flipper::Adapters::Memory.new
66
- adapter = Flipper::Adapters::Dalli.new(memory_adapter, dalli_client, 600)
67
- flipper = Flipper.new(adapter)
75
+ Flipper.configure do |config|
76
+ config.adapter do
77
+ dalli = Dalli::Client.new('localhost:11211')
78
+ adapter = Flipper::Adapters::Memory.new
79
+ Flipper::Adapters::Dalli.new(adapter, dalli, 600)
80
+ end
81
+ end
68
82
  ```
83
+
69
84
  ### RedisCache
70
85
 
71
86
  Applications using [Redis](https://redis.io/) via the [redis-rb](https://github.com/redis/redis-rb) client can take advantage of the RedisCache adapter.
@@ -75,12 +90,15 @@ Initialize `RedisCache` with a flipper [adapter](https://github.com/jnunemaker/
75
90
  Example using the RedisCache adapter with the Memory adapter and a TTL of 4800 seconds:
76
91
 
77
92
  ```ruby
78
- require 'flipper/adapters/redis_cache'
93
+ require 'flipper/adapters/redis_cache'
79
94
 
80
- redis = Redis.new(url: ENV['REDIS_URL'])
81
- memory_adapter = Flipper::Adapters::Memory.new
82
- adapter = Flipper::Adapters::RedisCache.new(memory_adapter, redis, 4800)
83
- flipper = Flipper.new(adapter)
95
+ Flipper.configure do |config|
96
+ config.adapter do
97
+ redis = Redis.new(url: ENV['REDIS_URL'])
98
+ memory_adapter = Flipper::Adapters::Memory.new
99
+ Flipper::Adapters::RedisCache.new(memory_adapter, redis, 4800)
100
+ end
101
+ end
84
102
  ```
85
103
 
86
104
  ### ActiveSupportCacheStore
@@ -105,10 +123,15 @@ Example using the ActiveSupportCacheStore adapter with ActiveSupport's [MemorySt
105
123
  require 'active_support/cache'
106
124
  require 'flipper/adapters/active_support_cache_store'
107
125
 
108
- memory_adapter = Flipper::Adapters::Memory.new
109
- cache = ActiveSupport::Cache::MemoryStore.new
110
- adapter = Flipper::Adapters::ActiveSupportCacheStore.new(memory_adapter, cache, expires_in: 5.minutes)
111
- flipper = Flipper.new(adapter)
126
+ Flipper.configure do |config|
127
+ config.adapter do
128
+ Flipper::Adapters::ActiveSupportCacheStore.new(
129
+ Flipper::Adapters::Memory.new,
130
+ ActiveSupport::Cache::MemoryStore.new # Or Rails.cache,
131
+ expires_in: 5.minutes
132
+ )
133
+ end
134
+ end
112
135
  ```
113
136
 
114
137
  Setting `expires_in` is optional and will set an expiration time on Flipper cache keys. If specified, all flipper keys will use this `expires_in` over the `expires_in` passed to your ActiveSupport cache constructor.
data/docs/http/README.md CHANGED
@@ -8,17 +8,18 @@ Initialize the HTTP adapter with a configuration Hash.
8
8
  ```ruby
9
9
  require 'flipper/adapters/http'
10
10
 
11
- configuration = {
12
- url: '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: 5,
17
- open_timeout: 2,
18
- }
19
-
20
- adapter = Flipper::Adapters::Http.new(configuration)
21
- flipper = Flipper.new(adapter)
11
+ Flipper.configure do |config|
12
+ config.adapter do
13
+ Flipper::Adapters::Http.new({
14
+ url: 'http://app.com/mount-point', # required
15
+ headers: { 'X-Custom-Header' => 'foo' },
16
+ basic_auth_username: 'user123',
17
+ basic_auth_password: 'password123'
18
+ read_timeout: 5,
19
+ open_timeout: 2,
20
+ })
21
+ end
22
+ end
22
23
  ```
23
24
 
24
25
  **Required keys**:
Binary file
@@ -5,17 +5,20 @@ A [read-only](https://github.com/jnunemaker/flipper/blob/master/lib/flipper/adap
5
5
  Use this adapter to wrap another adapter and raise an exception for any writes.
6
6
 
7
7
  Any attempted write raises `Flipper::Adapters::ReadOnly::WriteAttempted` with message `'write attempted while in read only mode'`
8
+
8
9
  ## Usage
10
+
9
11
  ```ruby
10
12
  # example wrapping memory adapter
11
13
  require 'flipper/adapters/read_only'
12
14
 
13
- memory_adapter = Flipper::Adapters::Memory.new
14
- read_only_adapter = Flipper::Adapters::ReadOnly.new(memory_adapter)
15
-
16
- flipper = Flipper.new(read_only_adapter)
15
+ Flipper.configure do |config|
16
+ config.adapter do
17
+ Flipper::Adapters::ReadOnly.new(Flipper::Adapters::Memory.new)
18
+ end
19
+ end
17
20
 
18
21
  # Enabling a feature
19
- > flipper[:dashboard_panel].enable
22
+ > Flipper[:dashboard_panel].enable
20
23
  => Flipper::Adapters::ReadOnly::WriteAttempted: write attempted while in read only mode
21
24
  ```