flipper 0.11.0.beta6 → 0.11.0.beta7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fc657f1ced7ca41760051223843e487c3c820277
4
- data.tar.gz: '0520502010855501979601516821cac277ce3891'
3
+ metadata.gz: 258c0cfa4877a2bea9e7927f5d39ed1339c3f698
4
+ data.tar.gz: 4402f1aa545f09f2bf0dd97937d6e7564ec6d008
5
5
  SHA512:
6
- metadata.gz: b9afe59c11ad41ec976ed8cb804929985afdb9e737146d9639510c75298ee88f1fb1573d92580f3504840a453e3cf84ed1a4b9d9c61ad5975fc1471d8096d34f
7
- data.tar.gz: a1c682c40e47feb582e74069aad67f261b9a2cb14b3cd0978a175a305e6fd31a062804514608c60dffe743a635d4037b7aba55a6410b12a68eaef8a9343506a1
6
+ metadata.gz: 7596ed84b459acc7b052a11e7a86e5be07d4bc52b083e31dcd14749b56e026f7a6ee0a6b3aac50fdc61950afcc764bdf64834bcecd4668baadc62e06a60d248b
7
+ data.tar.gz: 18a608871470cd7ae57db9b4dccf661e9ea8fe68e55efced9fea8cec26b9374a9c528b324516da9f263cad8cd4da28d697501f321d8f9a2b0280a351e1ed057c
data/Changelog.md CHANGED
@@ -23,6 +23,8 @@
23
23
  * Allow setting debug output of http adapter (https://github.com/jnunemaker/flipper/pull/256 and https://github.com/jnunemaker/flipper/pull/258).
24
24
  * Allow setting env key for middleware (https://github.com/jnunemaker/flipper/pull/259).
25
25
  * Added ActiveSupport cache store adapter for use with Rails.cache (https://github.com/jnunemaker/flipper/pull/265).
26
+ * Added support for up to 3 decimal places in percentage based rollouts (https://github.com/jnunemaker/flipper/pull/274).
27
+ * Removed Flipper::GroupNotRegistered error as it is now unused (https://github.com/jnunemaker/flipper/pull/270).
26
28
 
27
29
  ## 0.10.2
28
30
 
data/README.md CHANGED
@@ -41,26 +41,34 @@ The goal of the API for flipper was to have everything revolve around features a
41
41
 
42
42
  ```ruby
43
43
  require 'flipper'
44
-
45
- # pick an adapter
46
44
  require 'flipper/adapters/memory'
47
- adapter = Flipper::Adapters::Memory.new
48
45
 
49
- # get a handy dsl instance
50
- flipper = Flipper.new(adapter)
46
+ Flipper.configure do |config|
47
+ config.default do
48
+ # pick an adapter, this uses memory, any will do
49
+ adapter = Flipper::Adapters::Memory.new
51
50
 
52
- # grab a feature
53
- search = flipper[:search]
51
+ # pass adapter to handy DSL instance
52
+ Flipper.new(adapter)
53
+ end
54
+ end
54
55
 
55
- # check if that feature is enabled
56
- if search.enabled?
56
+ # check if search is enabled
57
+ if Flipper.enabled?(:search)
57
58
  puts 'Search away!'
58
59
  else
59
60
  puts 'No search for you!'
60
61
  end
61
62
 
62
63
  puts 'Enabling Search...'
63
- search.enable
64
+ Flipper.enable(:search)
65
+
66
+ # check if search is enabled
67
+ if Flipper.enabled?(:search)
68
+ puts 'Search away!'
69
+ else
70
+ puts 'No search for you!'
71
+ end
64
72
  ```
65
73
 
66
74
  Of course there are more [examples for you to peruse](examples/). You could also check out the [DSL](lib/flipper/dsl.rb) and [Feature](lib/flipper/feature.rb) classes for code/docs.
data/docs/Adapters.md CHANGED
@@ -5,6 +5,7 @@ I plan on supporting the adapters in the flipper repo. Other adapters are welcom
5
5
  ## Officially Supported
6
6
 
7
7
  * [ActiveRecord adapter](https://github.com/jnunemaker/flipper/blob/master/docs/active_record) - Rails 3, 4, and 5.
8
+ * [CacheStore adapter](https://github.com/jnunemaker/flipper/blob/master/docs/cache_store) - ActiveSupport::Cache::Store
8
9
  * [Cassanity adapter](https://github.com/jnunemaker/flipper-cassanity)
9
10
  * [Http adapter](https://github.com/jnunemaker/flipper/blob/master/docs/http)
10
11
  * [memory adapter](https://github.com/jnunemaker/flipper/blob/master/lib/flipper/adapters/memory.rb) – great for tests
data/docs/Optimization.md CHANGED
@@ -95,3 +95,34 @@ Example using the RedisCache adapter with the Memory adapter and a TTL of 4800 s
95
95
  adapter = Flipper::Adapters::RedisCache.new(memory_adapter, redis, 4800)
96
96
  flipper = Flipper.new(adapter)
97
97
  ```
98
+
99
+ ### CacheStore
100
+
101
+ Rails applications can cache Flipper calls in any [ActiveSupport::Cache::Store](http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html) implementation.
102
+
103
+ Add this line to your application's Gemfile:
104
+
105
+ gem 'flipper-cache-store'
106
+
107
+ And then execute:
108
+
109
+ $ bundle
110
+
111
+ Or install it yourself with:
112
+
113
+ $ gem install flipper-cache-store
114
+
115
+ Example using the CacheStore adapter with ActiveSupport's [MemoryStore](http://api.rubyonrails.org/classes/ActiveSupport/Cache/MemoryStore.html), Flipper's [Memory adapter](https://github.com/jnunemaker/flipper/blob/master/lib/flipper/adapters/memory.rb), and a TTL of 5 minutes.
116
+
117
+ ```ruby
118
+ require 'active_support/cache'
119
+ require 'flipper/adapters/memory'
120
+ require 'flipper/adapters/cache_store'
121
+
122
+ memory_adapter = Flipper::Adapters::Memory.new
123
+ cache = ActiveSupport::Cache::MemoryStore.new
124
+ adapter = Flipper::Adapters::CacheStore.new(memory_adapter, cache, expires_in: 5.minutes)
125
+ flipper = Flipper.new(adapter)
126
+ ```
127
+
128
+ 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/examples/basic.rb CHANGED
@@ -3,25 +3,29 @@ require File.expand_path('../example_setup', __FILE__)
3
3
  require 'flipper'
4
4
  require 'flipper/adapters/memory'
5
5
 
6
- # pick an adapter
7
- adapter = Flipper::Adapters::Memory.new
6
+ Flipper.configure do |config|
7
+ config.default do
8
+ # pick an adapter, this uses memory, any will do
9
+ adapter = Flipper::Adapters::Memory.new
8
10
 
9
- # get a handy dsl instance
10
- flipper = Flipper.new(adapter)
11
-
12
- # grab a feature
13
- search = flipper[:search]
14
-
15
- perform = lambda do
16
- # check if that feature is enabled
17
- if search.enabled?
18
- puts 'Search away!'
19
- else
20
- puts 'No search for you!'
11
+ # pass adapter to handy DSL instance
12
+ Flipper.new(adapter)
21
13
  end
22
14
  end
23
15
 
24
- perform.call
16
+ # check if search is enabled
17
+ if Flipper.enabled?(:search)
18
+ puts 'Search away!'
19
+ else
20
+ puts 'No search for you!'
21
+ end
22
+
25
23
  puts 'Enabling Search...'
26
- search.enable
27
- perform.call
24
+ Flipper.enable(:search)
25
+
26
+ # check if search is enabled
27
+ if Flipper.enabled?(:search)
28
+ puts 'Search away!'
29
+ else
30
+ puts 'No search for you!'
31
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../example_setup', __FILE__)
2
+
3
+ require 'flipper'
4
+ require 'flipper/adapters/memory'
5
+
6
+ # sets up default adapter so Flipper works like Flipper::DSL
7
+ Flipper.configure do |config|
8
+ config.default do
9
+ Flipper.new Flipper::Adapters::Memory.new
10
+ end
11
+ end
12
+
13
+ puts Flipper.enabled?(:search) # => false
14
+ Flipper.enable(:search)
15
+ puts Flipper.enabled?(:search) # => true
16
+ Flipper.disable(:search)
17
+
18
+ enabled_actor = Flipper::Actor.new("1")
19
+ disabled_actor = Flipper::Actor.new("2")
20
+ Flipper.enable_actor(:search, enabled_actor)
21
+
22
+ puts Flipper.enabled?(:search, enabled_actor)
23
+ puts Flipper.enabled?(:search, disabled_actor)
@@ -19,7 +19,7 @@ class User
19
19
  alias_method :flipper_id, :id
20
20
  end
21
21
 
22
- total = 10_000
22
+ total = 100_000
23
23
 
24
24
  # create array of fake users
25
25
  users = (1..total).map { |n| User.new(n) }
@@ -31,13 +31,12 @@ perform_test = lambda { |number|
31
31
  flipper[:stats].enabled?(user) ? true : nil
32
32
  }.compact
33
33
 
34
- actual = (enabled.size / total.to_f * 100).round(2)
34
+ actual = (enabled.size / total.to_f * 100).round(3)
35
35
 
36
36
  puts "percentage: #{actual.to_s.rjust(6, ' ')} vs #{number.to_s.rjust(3, ' ')}"
37
37
  }
38
38
 
39
39
  puts "percentage: Actual vs Hoped For"
40
-
41
- [1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99, 100].each do |number|
40
+ [0.001, 0.01, 0.1, 1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99, 100].each do |number|
42
41
  perform_test.call number
43
42
  end
@@ -10,7 +10,7 @@ logging = flipper[:logging]
10
10
  perform_test = lambda do |number|
11
11
  logging.enable flipper.time(number)
12
12
 
13
- total = 1_000
13
+ total = 100_000
14
14
  enabled = []
15
15
  disabled = []
16
16
 
@@ -18,7 +18,7 @@ perform_test = lambda do |number|
18
18
  logging.enabled? ? true : nil
19
19
  }.compact
20
20
 
21
- actual = (enabled.size / total.to_f * 100).round(2)
21
+ actual = (enabled.size / total.to_f * 100).round(3)
22
22
 
23
23
  # puts "#{enabled.size} / #{total}"
24
24
  puts "percentage: #{actual.to_s.rjust(6, ' ')} vs #{number.to_s.rjust(3, ' ')}"
@@ -26,6 +26,6 @@ end
26
26
 
27
27
  puts "percentage: Actual vs Hoped For"
28
28
 
29
- [1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99, 100].each do |number|
29
+ [0.001, 0.01, 0.1, 1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99, 100].each do |number|
30
30
  perform_test.call number
31
31
  end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/flipper/version', __FILE__)
3
+
4
+ flipper_cache_store_files = lambda do |file|
5
+ file =~ /cache_store/
6
+ end
7
+
8
+ Gem::Specification.new do |gem|
9
+ gem.authors = ['John Nunemaker']
10
+ gem.email = ['nunemaker@gmail.com']
11
+ gem.summary = 'ActiveSupport::Cache::Store adapter for Flipper'
12
+ gem.description = 'ActiveSupport::Cache::Store adapter for Flipper'
13
+ gem.license = 'MIT'
14
+ gem.homepage = 'https://github.com/jnunemaker/flipper'
15
+
16
+ gem.files = `git ls-files`.split("\n").select(&flipper_cache_store_files) + ['lib/flipper/version.rb']
17
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n").select(&flipper_cache_store_files)
18
+ gem.name = 'flipper-cache-store'
19
+ gem.require_paths = ['lib']
20
+ gem.version = Flipper::VERSION
21
+
22
+ gem.add_dependency 'flipper', "~> #{Flipper::VERSION}"
23
+ gem.add_dependency 'activesupport', '>= 3.2', '< 6'
24
+ end
data/lib/flipper.rb CHANGED
@@ -1,13 +1,62 @@
1
+ require "forwardable"
2
+
1
3
  module Flipper
4
+ extend self # rubocop:disable Style/ModuleFunction
5
+ extend Forwardable
6
+
2
7
  # Private: The namespace for all instrumented events.
3
8
  InstrumentationNamespace = :flipper
4
9
 
5
10
  # Public: Start here. Given an adapter returns a handy DSL to all the flipper
6
11
  # goodness. To see supported options, check out dsl.rb.
7
- def self.new(adapter, options = {})
12
+ def new(adapter, options = {})
8
13
  DSL.new(adapter, options)
9
14
  end
10
15
 
16
+ # Public: Configure flipper.
17
+ #
18
+ # Flipper.configure do |config|
19
+ # config.default { ... }
20
+ # end
21
+ #
22
+ # Yields Flipper::Configuration instance.
23
+ def configure
24
+ yield configuration if block_given?
25
+ end
26
+
27
+ # Public: Returns Flipper::Configuration instance.
28
+ def configuration
29
+ @configuration ||= Configuration.new
30
+ end
31
+
32
+ # Public: Sets Flipper::Configuration instance.
33
+ def configuration=(configuration)
34
+ @configuration = configuration
35
+ end
36
+
37
+ # Public: Default per thread flipper instance if configured. You should not
38
+ # need to use this directly as most of the Flipper::DSL methods are delegated
39
+ # from Flipper module itself. Instead of doing Flipper.instance.enabled?(:search),
40
+ # you can use Flipper.enabled?(:search) for the same result.
41
+ #
42
+ # Returns Flipper::DSL instance.
43
+ def instance
44
+ Thread.current[:flipper_instance] ||= configuration.default
45
+ end
46
+
47
+ # Public: All the methods delegated to instance. These should match the
48
+ # interface of Flipper::DSL.
49
+ def_delegators :instance,
50
+ :enabled?, :enable, :disable, :bool, :boolean,
51
+ :enable_actor, :disable_actor, :actor,
52
+ :enable_group, :disable_group,
53
+ :enable_percentage_of_actors, :disable_percentage_of_actors,
54
+ :actors, :percentage_of_actors,
55
+ :enable_percentage_of_time, :disable_percentage_of_time,
56
+ :time, :percentage_of_time,
57
+ :features, :feature, :[], :preload, :preload_all,
58
+ :add, :remove, :import
59
+
11
60
  # Public: Use this to register a group by name.
12
61
  #
13
62
  # name - The Symbol name of the group.
@@ -22,7 +71,7 @@ module Flipper
22
71
  #
23
72
  # Returns a Flipper::Group.
24
73
  # Raises Flipper::DuplicateGroup if the group is already registered.
25
- def self.register(name, &block)
74
+ def register(name, &block)
26
75
  group = Types::Group.new(name, &block)
27
76
  groups_registry.add(group.name, group)
28
77
  group
@@ -31,28 +80,28 @@ module Flipper
31
80
  end
32
81
 
33
82
  # Public: Returns a Set of registered Types::Group instances.
34
- def self.groups
83
+ def groups
35
84
  groups_registry.values.to_set
36
85
  end
37
86
 
38
87
  # Public: Returns a Set of symbols where each symbol is a registered
39
88
  # group name. If you just want the names, this is more efficient than doing
40
89
  # `Flipper.groups.map(&:name)`.
41
- def self.group_names
90
+ def group_names
42
91
  groups_registry.keys.to_set
43
92
  end
44
93
 
45
94
  # Public: Clears the group registry.
46
95
  #
47
96
  # Returns nothing.
48
- def self.unregister_groups
97
+ def unregister_groups
49
98
  groups_registry.clear
50
99
  end
51
100
 
52
101
  # Public: Check if a group exists
53
102
  #
54
103
  # Returns boolean
55
- def self.group_exists?(name)
104
+ def group_exists?(name)
56
105
  groups_registry.key?(name)
57
106
  end
58
107
 
@@ -65,22 +114,23 @@ module Flipper
65
114
  # Flipper.group(:admins)
66
115
  #
67
116
  # Returns Flipper::Group.
68
- def self.group(name)
117
+ def group(name)
69
118
  groups_registry.get(name) || Types::Group.new(name)
70
119
  end
71
120
 
72
121
  # Internal: Registry of all groups_registry.
73
- def self.groups_registry
122
+ def groups_registry
74
123
  @groups_registry ||= Registry.new
75
124
  end
76
125
 
77
126
  # Internal: Change the groups_registry registry.
78
- def self.groups_registry=(registry)
127
+ def groups_registry=(registry)
79
128
  @groups_registry = registry
80
129
  end
81
130
  end
82
131
 
83
132
  require 'flipper/actor'
133
+ require 'flipper/configuration'
84
134
  require 'flipper/adapter'
85
135
  require 'flipper/dsl'
86
136
  require 'flipper/errors'
@@ -0,0 +1,32 @@
1
+ module Flipper
2
+ class Configuration
3
+ def initialize
4
+ @default = -> { raise DefaultNotSet }
5
+ end
6
+
7
+ # Controls the default instance for flipper. When used with a block it
8
+ # assigns a new default block to use to generate an instance. When used
9
+ # without a block, it performs a block invocation and returns the result.
10
+ #
11
+ # configuration = Flipper::Configuration.new
12
+ # configuration.default # => raises DefaultNotSet error.
13
+ #
14
+ # # sets the default block to generate a new instance using Memory adapter
15
+ # configuration.default do
16
+ # require "flipper/adapters/memory"
17
+ # Flipper.new(Flipper::Adapters::Memory.new)
18
+ # end
19
+ #
20
+ # configuration.default # => Flipper::DSL instance using Memory adapter
21
+ #
22
+ # Returns result of default block invocation if called without block. If
23
+ # called with block, assigns the default block.
24
+ def default(&block)
25
+ if block_given?
26
+ @default = block
27
+ else
28
+ @default.call
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/flipper/dsl.rb CHANGED
@@ -217,7 +217,6 @@ module Flipper
217
217
  # name - The String or Symbol name of the feature.
218
218
  #
219
219
  # Returns an instance of Flipper::Group.
220
- # Raises Flipper::GroupNotRegistered if group has not been registered.
221
220
  def group(name)
222
221
  Flipper.group(name)
223
222
  end
@@ -12,6 +12,13 @@ module Flipper
12
12
  # Raised when attempting to declare a group name that has already been used.
13
13
  class DuplicateGroup < Error; end
14
14
 
15
- # Raised when attempting to access a group that is not registered.
16
- class GroupNotRegistered < Error; end
15
+ # Raised when default instance not configured but there is an attempt to
16
+ # use it.
17
+ class DefaultNotSet < Flipper::Error
18
+ def initialize(message = nil)
19
+ default = "Default flipper instance not configured. See " \
20
+ "Flipper.configure for how to configure the default instance."
21
+ super(message || default)
22
+ end
23
+ end
17
24
  end