feature 1.3.0 → 1.4.0

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: 19c7e68f322b7bd8ecc077e38301ca81f0101b98
4
- data.tar.gz: 6494be8fbf82513c8bc3584f5b79ee64db13dce8
3
+ metadata.gz: 7dfe050498795b0fa100aa76b2f366152762a73f
4
+ data.tar.gz: 4826e039f1642c887d1a62ce917d20cc54f597ec
5
5
  SHA512:
6
- metadata.gz: e2552d77a0338981f11f30520712345a6f0e1b45f827748004fcf1fe373e6f0304826fd433bdadf2e572812705d96c7b5bf9d4e9f254d57803016c182b5414dc
7
- data.tar.gz: 0b0208a6710fd63b2fdecc397a16895ad52cfc814465bc42ef2d49292e7bd242035794c652f803b13914fd0ef1d72b31f57980b61facaad31154b4f03bc06b97
6
+ metadata.gz: 0670fda64dac5f6a932cd5fa88d257b53269a5a304037a3b8f984e1f865411a5fe5df6ea6a7e3e2b23f9311a2d27be3aeb0d3faeaf611d555143c8ba854695e3
7
+ data.tar.gz: d434bc4e9f2977d8aa864531a0dab79059fe5682b74d0194464e9e2fcae0381efed9514c565702b529315d3e755189ad04a993193fd603c16bdd2f68e95b0646
@@ -1,3 +1,10 @@
1
+ ## 1.4.0 (2016-06-11)
2
+
3
+ * possibility to refresh feature list after certain time (enc)
4
+ * call to get all active features (pmeskers)
5
+ * Improve and prettify README (glaucocustodio)
6
+ * Fixing typos in README (adarsh)
7
+
1
8
  ## 1.3.0 (2015-06-12)
2
9
 
3
10
  * Support testing with multiple features (stevenwilkin)
data/Gemfile CHANGED
@@ -7,7 +7,10 @@ group :test do
7
7
  gem 'rspec-mocks'
8
8
  gem 'coveralls', require: false
9
9
  gem 'rubocop', require: false
10
+ gem 'timecop'
10
11
  gem 'fakeredis'
11
- gem 'mutant'
12
- gem 'mutant-rspec'
12
+ if RUBY_VERSION >= '2.1'
13
+ gem 'mutant'
14
+ gem 'mutant-rspec'
15
+ end
13
16
  end
data/README.md CHANGED
@@ -11,13 +11,13 @@ Feature is a battle-tested [feature toggle](http://martinfowler.com/bliki/Featur
11
11
 
12
12
  The feature toggle functionality has to be configured by feature repositories. A feature repository simply provides lists of active features (symbols!). Unknown features are assumed inactive.
13
13
 
14
- With this approach Feature is higly configurable and not bound to a specific kind of configuration.
14
+ With this approach Feature is highly configurable and not bound to a specific kind of configuration.
15
15
 
16
- **NOTE:** Ruby 1.9 is supported explicitly only until version 1.2.0. Later version may require 2+.
16
+ **NOTE:** The current gem version works with Ruby 2+ and supports Ruby on Rails 4+.
17
17
 
18
- **NOTE:** Ruby 1.8 is only supported until version 0.7.0. Later Versions require Ruby 1.9+.
18
+ **NOTE:** Ruby 1.9 is supported until version 1.2.0, Ruby 1.8 is supported until version 0.7.0.
19
19
 
20
- **NOTE:** Using feature with ActiveRecord and Rails 3 MAY work. Version 1.1.0 supports Rails 3.
20
+ **NOTE:** ActiveRecord / Rails 3 is supported until version 1.1.0.
21
21
 
22
22
  ## Installation
23
23
 
@@ -26,41 +26,53 @@ With this approach Feature is higly configurable and not bound to a specific kin
26
26
  ## How to use
27
27
 
28
28
  * Setup Feature
29
- * Create a repository (see examples below)
30
- * Set repository to Feature
29
+ * Create a repository (for more infos about configuration backends, see section below)
30
+ ```ruby
31
+ require 'feature'
32
+ repo = Feature::Repository::SimpleRepository.new
33
+ ```
31
34
 
32
- Feature.set_repository(your_repository)
35
+ * Set repository to Feature
36
+ ```ruby
37
+ Feature.set_repository(repo)
38
+ ```
33
39
 
34
40
  * Use Feature in your production code
41
+ ```ruby
42
+ Feature.active?(:feature_name) # => true/false
35
43
 
36
- Feature.active?(:feature_name) # => true/false
44
+ Feature.inactive?(:feature_name) # => true/false
37
45
 
38
- Feature.inactive?(:feature_name) # => true/false
46
+ Feature.active_features # => [:list, :of, :features]
39
47
 
40
- Feature.with(:feature_name) do
41
- # code
42
- end
48
+ Feature.with(:feature_name) do
49
+ # code
50
+ end
43
51
 
44
- Feature.without(:feature_name) do
45
- # code
46
- end
52
+ Feature.without(:feature_name) do
53
+ # code
54
+ end
47
55
 
48
- Feature.switch(:feature_name, value_true, value_false) # => returns value_true if :feature_name is active, otherwise value_false
56
+ # this returns value_true if :feature_name is active, otherwise value_false
57
+ Feature.switch(:feature_name, value_true, value_false)
49
58
 
50
- # May also take Procs (here in Ruby 1.9 lambda syntax), returns code evaluation result.
51
- Feature.switch(:feature_name, -> { code... }, -> { code... })
59
+ # switch may also take Procs that will be evaluated and it's result returned.
60
+ Feature.switch(:feature_name, -> { code... }, -> { code... })
61
+ ```
52
62
 
53
63
  * Use Feature in your test code (for reliable testing of feature depending code)
64
+ ```ruby
65
+ require 'feature/testing'
54
66
 
55
- require 'feature/testing'
67
+ Feature.run_with_activated(:feature) do
68
+ # your test code
69
+ end
56
70
 
57
- Feature.run_with_activated(:feature) do
58
- # your test code
59
- end
60
-
61
- Feature.run_with_deactivated(:feature, :another_feature) do
62
- # your test code
63
- end
71
+ # you also can give a list of features
72
+ Feature.run_with_deactivated(:feature, :another_feature) do
73
+ # your test code
74
+ end
75
+ ```
64
76
 
65
77
  * Feature-toggle caching
66
78
 
@@ -68,123 +80,124 @@ With this approach Feature is higly configurable and not bound to a specific kin
68
80
  underlying repository the first time you try to check whether a
69
81
  feature is set or not.
70
82
 
71
- * Subsequent toggle-status checks will access the cached, in-memory
72
- representation of the toggle status, so changes to toggles in the
83
+ * Subsequent calls to Feature will access the cached in-memory
84
+ representation of the list of features. So changes to toggles in the
73
85
  underlying repository would not be reflected in the application
74
- until you restart the application or manally call
75
-
76
- Feature.refresh!
86
+ until you restart the application or manually call
87
+ ```ruby
88
+ Feature.refresh!
89
+ ```
77
90
 
78
91
  * You can optionally pass in true as a second argument on
79
92
  set_repository, to force Feature to auto-refresh the feature list
80
93
  on every feature-toggle check you make.
81
-
82
- Feature.set_repository(your_repository, true)
83
-
84
- ## Examples
85
-
86
- ### Vanilla Ruby using SimpleRepository
87
-
88
- # setup code
89
- require 'feature'
90
-
91
- repo = Feature::Repository::SimpleRepository.new
92
- repo.add_active_feature :be_nice
93
-
94
- Feature.set_repository repo
95
-
96
- # production code
97
- Feature.active?(:be_nice)
98
- # => true
99
-
100
- Feature.with(:be_nice) do
101
- puts "you can read this"
102
- end
103
-
104
- ### Ruby or Rails using RedisRepository
105
-
106
- # See here to learn how to configure redis: https://github.com/redis/redis-rb
107
-
108
- # File: Gemfile
109
- gem 'feature'
110
- gem 'redis'
111
-
112
- # setup code (or Rails initializer: config/initializers/feature.rb)
113
- require 'feature'
114
-
115
- repo = Feature::Repository::RedisRepository.new("feature_toggles")
116
- Feature.set_repository repo
117
-
118
- # production code
119
- Feature.active?(:be_nice)
120
- # => true
121
-
122
- Feature.with(:be_nice) do
123
- puts "you can read this"
124
- end
125
-
126
- # see all features in Redis
127
- Redis.current.hgetall("feature_toggles")
128
-
129
- # add/toggle features in Redis
130
- Redis.current.hset("feature_toggles", "ActiveFeature", true)
131
- Redis.current.hset("feature_toggles", "InActiveFeature", false)
132
-
133
- ### Rails using YamlRepository
134
-
135
- # File: Gemfile
136
- gem 'feature'
137
-
138
- # File: config/feature.yml
139
- features:
140
- an_active_feature: true
141
- an_inactive_feature: false
142
-
143
- # File: config/initializers/feature.rb
144
- repo = Feature::Repository::YamlRepository.new("#{Rails.root}/config/feature.yml")
145
- Feature.set_repository repo
146
-
147
- # File: app/views/example/index.html.erb
148
- <% if Feature.active?(:an_active_feature) %>
149
- <%# Feature implementation goes here %>
150
- <% end %>
94
+ ```ruby
95
+ Feature.set_repository(your_repository, true)
96
+ ```
97
+
98
+ * You can also optionally pass in a number as second argument on
99
+ set_repository, to force Feature to refresh the feature list
100
+ after X seconds. This will be done only on demand by a request.
101
+ ```ruby
102
+ Feature.set_repository(your_repository, 60)
103
+ ```
104
+
105
+ ## How to setup different backends
106
+
107
+ ### SimpleRepository (in-memory)
108
+ ```ruby
109
+ # File: Gemfile
110
+ gem 'feature'
111
+ ```
112
+
113
+ ```ruby
114
+ # setup code
115
+ require 'feature'
116
+
117
+ repo = Feature::Repository::SimpleRepository.new
118
+ repo.add_active_feature :be_nice
119
+
120
+ Feature.set_repository repo
121
+ ```
122
+
123
+ ### RedisRepository (features configured in redis server)
124
+ ```ruby
125
+ # See here to learn how to configure redis: https://github.com/redis/redis-rb
126
+
127
+ # File: Gemfile
128
+ gem 'feature'
129
+ gem 'redis'
130
+ ```
131
+
132
+ ```ruby
133
+ # setup code (or Rails initializer: config/initializers/feature.rb)
134
+ require 'feature'
135
+
136
+ # "feature_toggles" will be the key name in redis
137
+ repo = Feature::Repository::RedisRepository.new("feature_toggles")
138
+ Feature.set_repository repo
139
+
140
+ # add/toggle features in Redis
141
+ Redis.current.hset("feature_toggles", "ActiveFeature", true)
142
+ Redis.current.hset("feature_toggles", "InActiveFeature", false)
143
+ ```
144
+
145
+ ### YamlRepository (features configured in static yml file)
146
+ ```ruby
147
+ # File: Gemfile
148
+ gem 'feature'
149
+ ```
150
+
151
+ ```
152
+ # File: config/feature.yml
153
+ features:
154
+ an_active_feature: true
155
+ an_inactive_feature: false
156
+ ```
157
+
158
+ ```ruby
159
+ # setup code (or Rails initializer: config/initializers/feature.rb)
160
+ repo = Feature::Repository::YamlRepository.new("#{Rails.root}/config/feature.yml")
161
+ Feature.set_repository repo
162
+ ```
151
163
 
152
164
  You may also specify a Rails environment to use a new feature in development and test, but not production:
153
-
154
- # File: config/feature.yml
155
- development:
156
- features:
157
- a_new_feature: true
158
- test:
159
- features:
160
- a_new_feature: true
161
- production:
162
- features:
163
- a_new_feature: false
164
-
165
- # File: config/initializers/feature.rb
166
- repo = Feature::Repository::YamlRepository.new("#{Rails.root}/config/feature.yml", Rails.env)
167
- Feature.set_repository repo
168
-
169
- ### Rails using ActiveRecordRepository
170
-
171
- # File: Gemfile
172
- gem 'feature'
173
-
174
- # Run generator and migrations
175
- $ rails g feature:install
176
- $ rake db:migrate
177
-
178
- # Add Features to table FeaturesToggle for example in
179
- # File: db/schema.rb
180
- FeatureToggle.create!(name: "ActiveFeature", active: true)
181
- FeatureToggle.create!(name: "InActiveFeature", active: false)
182
-
183
- # or in initializer
184
- # File: config/initializers/feature.rb
185
- repo.add_active_feature(:active_feature)
186
-
187
- # File: app/views/example/index.html.erb
188
- <% if Feature.active?(:an_active_feature) %>
189
- <%# Feature implementation goes here %>
190
- <% end %>
165
+ ```
166
+ # File: config/feature.yml
167
+ test:
168
+ features:
169
+ a_new_feature: true
170
+ production:
171
+ features:
172
+ a_new_feature: false
173
+ ```
174
+
175
+ ```ruby
176
+ # File: config/initializers/feature.rb
177
+ repo = Feature::Repository::YamlRepository.new("#{Rails.root}/config/feature.yml", Rails.env)
178
+ Feature.set_repository repo
179
+ ```
180
+
181
+ ### ActiveRecordRepository (features configured in a database) using Rails
182
+
183
+ ```ruby
184
+ # File: Gemfile
185
+ gem 'feature'
186
+ ```
187
+
188
+ ```
189
+ # Run generator and migrations
190
+ $ rails g feature:install
191
+ $ rake db:migrate
192
+ ```
193
+
194
+ ```ruby
195
+ # Add Features to table FeaturesToggle for example in
196
+ # File: db/schema.rb
197
+ FeatureToggle.create!(name: "ActiveFeature", active: true)
198
+ FeatureToggle.create!(name: "InActiveFeature", active: false)
199
+
200
+ # or in initializer
201
+ # File: config/initializers/feature.rb
202
+ repo.add_active_feature(:active_feature)
203
+ ```
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'rake/testtask'
2
2
  require 'rspec/core/rake_task'
3
3
  require 'rubocop/rake_task'
4
- require 'mutant'
5
4
 
6
5
  RuboCop::RakeTask.new
7
6
 
@@ -11,8 +10,9 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
11
10
  end
12
11
 
13
12
  task :mutant do
13
+ require 'mutant'
14
14
  result = Mutant::CLI.run(%w(--include lib --require feature --use rspec Feature*))
15
- fail unless result == Mutant::CLI::EXIT_SUCCESS
15
+ raise unless result == Mutant::CLI::EXIT_SUCCESS
16
16
  end
17
17
 
18
18
  task default: [:spec, :rubocop]
@@ -31,16 +31,22 @@ module Feature
31
31
  # The given repository has to respond to method 'active_features' with an array of symbols
32
32
  #
33
33
  # @param [Object] repository the repository to get the features from
34
- # @param [Boolean] auto_refresh optional (default: false) - refresh feature toggles on every check if set true
34
+ # @param [Boolean|Integer] refresh optional (default: false) - auto refresh or refresh after given number of seconds
35
35
  #
36
- def self.set_repository(repository, auto_refresh = false)
36
+ def self.set_repository(repository, refresh = false)
37
37
  unless repository.respond_to?(:active_features)
38
- fail ArgumentError, 'given repository does not respond to active_features'
38
+ raise ArgumentError, 'given repository does not respond to active_features'
39
39
  end
40
40
 
41
- @auto_refresh = auto_refresh
42
41
  @perform_initial_refresh = true
43
42
  @repository = repository
43
+ if [true, false].include?(refresh)
44
+ @auto_refresh = refresh
45
+ else
46
+ @auto_refresh = false
47
+ @refresh_after = refresh
48
+ @next_refresh_after = Time.now + @refresh_after
49
+ end
44
50
  end
45
51
 
46
52
  # Refreshes list of active features from repository.
@@ -48,6 +54,7 @@ module Feature
48
54
  #
49
55
  def self.refresh!
50
56
  @active_features = @repository.active_features
57
+ @next_refresh_after = Time.now + @refresh_after if @refresh_after
51
58
  @perform_initial_refresh = false
52
59
  end
53
60
 
@@ -58,11 +65,7 @@ module Feature
58
65
  # @return [Boolean]
59
66
  #
60
67
  def self.active?(feature)
61
- fail 'missing Repository for obtaining feature lists' unless @repository
62
-
63
- refresh! if @auto_refresh || @perform_initial_refresh
64
-
65
- @active_features.include?(feature)
68
+ active_features.include?(feature)
66
69
  end
67
70
 
68
71
  # Requests if feature is inactive (or unknown)
@@ -79,7 +82,7 @@ module Feature
79
82
  # @param [Symbol] feature
80
83
  #
81
84
  def self.with(feature)
82
- fail ArgumentError, "no block given to #{__method__}" unless block_given?
85
+ raise ArgumentError, "no block given to #{__method__}" unless block_given?
83
86
 
84
87
  yield if active?(feature)
85
88
  end
@@ -89,7 +92,7 @@ module Feature
89
92
  # @param [Symbol] feature
90
93
  #
91
94
  def self.without(feature)
92
- fail ArgumentError, "no block given to #{__method__}" unless block_given?
95
+ raise ArgumentError, "no block given to #{__method__}" unless block_given?
93
96
 
94
97
  yield if inactive?(feature)
95
98
  end
@@ -107,4 +110,16 @@ module Feature
107
110
  l2.instance_of?(Proc) ? l2.call : l2
108
111
  end
109
112
  end
113
+
114
+ # Return list of active feature flags.
115
+ #
116
+ # @return [Array] list of symbols
117
+ #
118
+ def self.active_features
119
+ raise 'missing Repository for obtaining feature lists' unless @repository
120
+
121
+ refresh! if @auto_refresh || @perform_initial_refresh || (@next_refresh_after && Time.now > @next_refresh_after)
122
+
123
+ @active_features
124
+ end
110
125
  end
@@ -39,7 +39,7 @@ module Feature
39
39
  # @param [Sybmol] feature the feature to be checked
40
40
  #
41
41
  def check_feature_is_not_symbol(feature)
42
- fail ArgumentError, "#{feature} is not a symbol" unless feature.instance_of?(Symbol)
42
+ raise ArgumentError, "#{feature} is not a symbol" unless feature.instance_of?(Symbol)
43
43
  end
44
44
  private :check_feature_is_not_symbol
45
45
 
@@ -49,7 +49,7 @@ module Feature
49
49
  # @param [Symbol] feature the feature to be checked
50
50
  #
51
51
  def check_feature_already_in_list(feature)
52
- fail ArgumentError, "feature :#{feature} already added" if @model.exists?(feature.to_s)
52
+ raise ArgumentError, "feature :#{feature} already added" if @model.exists?(name: feature.to_s)
53
53
  end
54
54
  private :check_feature_already_in_list
55
55
  end
@@ -10,12 +10,15 @@ module Feature
10
10
  # the Redis hash that will store all of your feature toggles.
11
11
  #
12
12
  class RedisRepository
13
+ attr_writer :redis
14
+
13
15
  # Constructor
14
16
  #
15
17
  # @param redis_key the key of the redis hash where all the toggles will be stored
16
18
  #
17
- def initialize(redis_key)
19
+ def initialize(redis_key, client = nil)
18
20
  @redis_key = redis_key
21
+ @redis = client unless client.nil?
19
22
  end
20
23
 
21
24
  # Returns list of active features
@@ -23,7 +26,7 @@ module Feature
23
26
  # @return [Array<Symbol>] list of active features
24
27
  #
25
28
  def active_features
26
- Redis.current.hgetall(@redis_key).select { |_k, v| v.to_s == 'true' }.map { |k, _v| k.to_sym }
29
+ redis.hgetall(@redis_key).select { |_k, v| v.to_s == 'true' }.map { |k, _v| k.to_sym }
27
30
  end
28
31
 
29
32
  # Add an active feature to repository
@@ -33,7 +36,7 @@ module Feature
33
36
  def add_active_feature(feature)
34
37
  check_feature_is_not_symbol(feature)
35
38
  check_feature_already_in_list(feature)
36
- Redis.current.hset(@redis_key, feature, true)
39
+ redis.hset(@redis_key, feature, true)
37
40
  end
38
41
 
39
42
  # Checks that given feature is a symbol, raises exception otherwise
@@ -41,7 +44,7 @@ module Feature
41
44
  # @param [Sybmol] feature the feature to be checked
42
45
  #
43
46
  def check_feature_is_not_symbol(feature)
44
- fail ArgumentError, "#{feature} is not a symbol" unless feature.instance_of?(Symbol)
47
+ raise ArgumentError, "#{feature} is not a symbol" unless feature.instance_of?(Symbol)
45
48
  end
46
49
  private :check_feature_is_not_symbol
47
50
 
@@ -51,9 +54,18 @@ module Feature
51
54
  # @param [Symbol] feature the feature to be checked
52
55
  #
53
56
  def check_feature_already_in_list(feature)
54
- fail ArgumentError, "feature :#{feature} already added" if Redis.current.hexists(@redis_key, feature)
57
+ raise ArgumentError, "feature :#{feature} already added" if redis.hexists(@redis_key, feature)
55
58
  end
56
59
  private :check_feature_already_in_list
60
+
61
+ # Returns the currently specified redis client
62
+ #
63
+ # @return [Redis] Currently set redis client
64
+ #
65
+ def redis
66
+ @redis ||= Redis.current
67
+ end
68
+ private :redis
57
69
  end
58
70
  end
59
71
  end
@@ -39,7 +39,7 @@ module Feature
39
39
  # @param [Sybmol] feature the feature to be checked
40
40
  #
41
41
  def check_feature_is_not_symbol(feature)
42
- fail ArgumentError, "#{feature} is not a symbol" unless feature.instance_of?(Symbol)
42
+ raise ArgumentError, "#{feature} is not a symbol" unless feature.instance_of?(Symbol)
43
43
  end
44
44
  private :check_feature_is_not_symbol
45
45
 
@@ -49,7 +49,7 @@ module Feature
49
49
  # @param [Symbol] feature the feature to be checked
50
50
  #
51
51
  def check_feature_already_in_list(feature)
52
- fail ArgumentError, "feature :#{feature} already added" if @active_features.include?(feature)
52
+ raise ArgumentError, "feature :#{feature} already added" if @active_features.include?(feature)
53
53
  end
54
54
  private :check_feature_already_in_list
55
55
  end
@@ -66,7 +66,7 @@ module Feature
66
66
  data = data[selector] unless selector.empty?
67
67
 
68
68
  if !data.is_a?(Hash) || !data.key?('features')
69
- fail ArgumentError, 'yaml config does not contain proper config'
69
+ raise ArgumentError, 'yaml config does not contain proper config'
70
70
  end
71
71
 
72
72
  return [] unless data['features']
@@ -84,7 +84,7 @@ module Feature
84
84
  def check_valid_feature_data(features)
85
85
  features.values.each do |value|
86
86
  unless [true, false].include?(value)
87
- fail ArgumentError, "#{value} is not allowed value in config, use true/false"
87
+ raise ArgumentError, "#{value} is not allowed value in config, use true/false"
88
88
  end
89
89
  end
90
90
  end
@@ -22,7 +22,7 @@ describe Feature::Repository::ActiveRecordRepository do
22
22
  end
23
23
 
24
24
  it 'should add an active feature' do
25
- expect(@features).to receive(:exists?).with('feature_a').and_return(false)
25
+ expect(@features).to receive(:exists?).with(name: 'feature_a').and_return(false)
26
26
  expect(@features).to receive(:create!).with(name: 'feature_a', active: true)
27
27
 
28
28
  @repository.add_active_feature :feature_a
@@ -27,6 +27,12 @@ describe Feature do
27
27
  end
28
28
  end.to raise_error('missing Repository for obtaining feature lists')
29
29
  end
30
+
31
+ it 'should raise an exception when calling active_features' do
32
+ expect do
33
+ Feature.active_features
34
+ end.to raise_error('missing Repository for obtaining feature lists')
35
+ end
30
36
  end
31
37
 
32
38
  context 'setting Repository' do
@@ -75,6 +81,31 @@ describe Feature do
75
81
  Feature.active?(:feature_a)
76
82
  end
77
83
  end
84
+
85
+ context 'with timeout set to 30 seconds' do
86
+ before(:each) do
87
+ Timecop.freeze(Time.now)
88
+ Feature.set_repository @repository, 30
89
+ @repository.add_active_feature(:feature_a)
90
+ Feature.active?(:feature_a)
91
+ end
92
+
93
+ after(:each) do
94
+ Timecop.return
95
+ end
96
+
97
+ it 'should not update after 10 seconds' do
98
+ Timecop.freeze(Time.now + 10)
99
+ expect(@repository).not_to receive(:active_features)
100
+ Feature.active?(:feature_a)
101
+ end
102
+
103
+ it 'should update after 40 seconds' do
104
+ Timecop.freeze(Time.now + 40)
105
+ expect(@repository).to receive(:active_features).and_return(@repository.active_features)
106
+ Feature.active?(:feature_a)
107
+ end
108
+ end
78
109
  end
79
110
 
80
111
  context 'refresh features' do
@@ -190,5 +221,11 @@ describe Feature do
190
221
  end
191
222
  end
192
223
  end
224
+
225
+ describe 'active_features' do
226
+ it 'should return an array of active feature flags' do
227
+ expect(Feature.active_features).to eq([:feature_active])
228
+ end
229
+ end
193
230
  end
194
231
  end
@@ -37,4 +37,10 @@ describe Feature::Repository::RedisRepository do
37
37
  @repository.add_active_feature :feature_a
38
38
  end.to raise_error(ArgumentError, 'feature :feature_a already added')
39
39
  end
40
+
41
+ let(:specified_redis) { double }
42
+ let(:repo) { RedisRepository.new('application_features', specified_redis) }
43
+ it 'should allow you to specify the redis instance to use' do
44
+ expect(repo.send(:redis)).to eq specified_redis
45
+ end
40
46
  end
@@ -1,4 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rails', '~> 4.1.4'
4
- gem 'railties'
3
+ gem 'rails', '~> 4.2.1'
@@ -1,4 +1,5 @@
1
1
  require 'pathname'
2
+ require 'timecop'
2
3
  require 'coveralls'
3
4
  require 'fakeredis/rspec'
4
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feature
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Gerdes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-12 00:00:00.000000000 Z
11
+ date: 2016-06-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: github@mgsnova.de
@@ -36,7 +36,6 @@ files:
36
36
  - spec/feature/testing_spec.rb
37
37
  - spec/feature/yaml_repository_spec.rb
38
38
  - spec/integration/rails/gemfiles/rails4.gemfile
39
- - spec/integration/rails/gemfiles/rails4.gemfile.lock
40
39
  - spec/integration/rails/test-against-several-rails-versions.sh
41
40
  - spec/integration/rails/test-against-specific-rails-version.sh
42
41
  - spec/spec_helper.rb
@@ -60,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
59
  version: '0'
61
60
  requirements: []
62
61
  rubyforge_project:
63
- rubygems_version: 2.4.8
62
+ rubygems_version: 2.5.1
64
63
  signing_key:
65
64
  specification_version: 4
66
65
  summary: Feature Toggle library for ruby
@@ -1,85 +0,0 @@
1
- GEM
2
- remote: https://rubygems.org/
3
- specs:
4
- actionmailer (4.1.4)
5
- actionpack (= 4.1.4)
6
- actionview (= 4.1.4)
7
- mail (~> 2.5.4)
8
- actionpack (4.1.4)
9
- actionview (= 4.1.4)
10
- activesupport (= 4.1.4)
11
- rack (~> 1.5.2)
12
- rack-test (~> 0.6.2)
13
- actionview (4.1.4)
14
- activesupport (= 4.1.4)
15
- builder (~> 3.1)
16
- erubis (~> 2.7.0)
17
- activemodel (4.1.4)
18
- activesupport (= 4.1.4)
19
- builder (~> 3.1)
20
- activerecord (4.1.4)
21
- activemodel (= 4.1.4)
22
- activesupport (= 4.1.4)
23
- arel (~> 5.0.0)
24
- activesupport (4.1.4)
25
- i18n (~> 0.6, >= 0.6.9)
26
- json (~> 1.7, >= 1.7.7)
27
- minitest (~> 5.1)
28
- thread_safe (~> 0.1)
29
- tzinfo (~> 1.1)
30
- arel (5.0.1.20140414130214)
31
- builder (3.2.2)
32
- erubis (2.7.0)
33
- hike (1.2.3)
34
- i18n (0.6.11)
35
- json (1.8.1)
36
- mail (2.5.4)
37
- mime-types (~> 1.16)
38
- treetop (~> 1.4.8)
39
- mime-types (1.25.1)
40
- minitest (5.4.0)
41
- multi_json (1.10.1)
42
- polyglot (0.3.5)
43
- rack (1.5.2)
44
- rack-test (0.6.2)
45
- rack (>= 1.0)
46
- rails (4.1.4)
47
- actionmailer (= 4.1.4)
48
- actionpack (= 4.1.4)
49
- actionview (= 4.1.4)
50
- activemodel (= 4.1.4)
51
- activerecord (= 4.1.4)
52
- activesupport (= 4.1.4)
53
- bundler (>= 1.3.0, < 2.0)
54
- railties (= 4.1.4)
55
- sprockets-rails (~> 2.0)
56
- railties (4.1.4)
57
- actionpack (= 4.1.4)
58
- activesupport (= 4.1.4)
59
- rake (>= 0.8.7)
60
- thor (>= 0.18.1, < 2.0)
61
- rake (10.3.2)
62
- sprockets (2.12.1)
63
- hike (~> 1.2)
64
- multi_json (~> 1.0)
65
- rack (~> 1.0)
66
- tilt (~> 1.1, != 1.3.0)
67
- sprockets-rails (2.1.3)
68
- actionpack (>= 3.0)
69
- activesupport (>= 3.0)
70
- sprockets (~> 2.8)
71
- thor (0.19.1)
72
- thread_safe (0.3.4)
73
- tilt (1.4.1)
74
- treetop (1.4.15)
75
- polyglot
76
- polyglot (>= 0.3.1)
77
- tzinfo (1.2.1)
78
- thread_safe (~> 0.1)
79
-
80
- PLATFORMS
81
- ruby
82
-
83
- DEPENDENCIES
84
- rails (~> 4.1.4)
85
- railties