feature 1.3.0 → 1.4.0

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 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