flipflop 2.3.1 → 2.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
- SHA1:
3
- metadata.gz: 79ce3ddc4c05be4f6b655519b73fc592b749177a
4
- data.tar.gz: 9de114a7fa334e5689d9bb49e6b2c0e0189b59b4
2
+ SHA256:
3
+ metadata.gz: 2d991f9cd5e93e4a837c0e6835da5ae2339498bf74a26fc6e21cee4503793ca6
4
+ data.tar.gz: 943ba8e6ea38bf2afbc45454890f8111a3b9029383018e5ddf3a76f8faac0732
5
5
  SHA512:
6
- metadata.gz: d89175f3cdf7c36f31fa22ec6b3174bf3d69399ec2ad58d1c1c68bbb5e239456b85c3386144414e5e40ce87d4c504f49cdbc54293aa5b9659dedcba237b94e9c
7
- data.tar.gz: d5a233ec2f53cdfb4d1aacd6afda3b385618887cfb524a6f7fc6de5eb0ad2ad05b949080a34e8e48eab5f4c18fd6dae571affee63ca576533ebf6277f153360c
6
+ metadata.gz: a81cbf3b37f9d91ec310bc971eec5c06b2d4b0581bd42191366503782bb8d95ef6b51fef33588bd28ec571a57ebc03f51cd1c5f9514ac8151f1a855e4072e085
7
+ data.tar.gz: 30a184287b36b7a346cc72fb0bf4f2ed4cb59083461f3859d70d1ec9908c37b3c1b65e54dc3536ed472fed85f94465ea191c6d4eeb7b049679b4056cb3585b05
data/.travis.yml CHANGED
@@ -1,38 +1,49 @@
1
1
  language: ruby
2
+ cache: bundler
2
3
  rvm:
3
- - 2.4.0
4
- - 2.3.0
5
- - jruby-9.1.2.0
4
+ - 2.5.0
5
+ - 2.4.2
6
+ - 2.3.5
7
+ - jruby-9.1.13.0
6
8
  - ruby-head
7
9
  - jruby-head
8
10
  env:
9
11
  - RAILS_VERSION=master
10
12
  - RAILS_VERSION=master RAILS_API_ONLY=1
13
+ - RAILS_VERSION=5.2
14
+ - RAILS_VERSION=5.2 RAILS_API_ONLY=1
15
+ - RAILS_VERSION=5.1
16
+ - RAILS_VERSION=5.1 RAILS_API_ONLY=1
11
17
  - RAILS_VERSION=5.0
12
18
  - RAILS_VERSION=5.0 RAILS_API_ONLY=1
13
19
  matrix:
14
20
  include:
15
- - rvm: 2.3.0
21
+ - rvm: 2.3.5
16
22
  env: RAILS_VERSION=4.2
17
- - rvm: 2.2.6
23
+ - rvm: 2.2.8
18
24
  env: RAILS_VERSION=4.2
19
- - rvm: 2.1.9
25
+ - rvm: 2.1.10
20
26
  env: RAILS_VERSION=4.2
21
27
  - rvm: 2.0.0
22
28
  env: RAILS_VERSION=4.2
23
- - rvm: 2.3.0
29
+ - rvm: 2.3.5
24
30
  env: RAILS_VERSION=4.1
25
- - rvm: 2.2.6
31
+ - rvm: 2.2.8
26
32
  env: RAILS_VERSION=4.1
27
- - rvm: 2.1.9
33
+ - rvm: 2.1.10
28
34
  env: RAILS_VERSION=4.1
29
35
  - rvm: 2.0.0
30
36
  env: RAILS_VERSION=4.1
37
+ exclude:
38
+ - rvm: 2.3.5
39
+ env: RAILS_VERSION=master
40
+ - rvm: 2.3.5
41
+ env: RAILS_VERSION=master RAILS_API_ONLY=1
31
42
  allow_failures:
32
- - rvm: jruby-9.1.2.0
43
+ - rvm: jruby-9.1.13.0
33
44
  - rvm: ruby-head
34
45
  - rvm: jruby-head
35
- before_deploy: rake assets:compile
46
+ before_deploy: bundle exec rake assets:compile
36
47
  deploy:
37
48
  provider: rubygems
38
49
  api_key:
@@ -41,4 +52,4 @@ deploy:
41
52
  on:
42
53
  tags: true
43
54
  repo: voormedia/flipflop
44
- ruby: 2.3.0
55
+ ruby: 2.3.5
data/CHANGES.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 2.4.0
2
+
3
+ * Add location of feature definition.
4
+ * Raise error for undefined feature or strategy keys. This change can potentially break test cases that use dummy keys.
5
+
1
6
  ## 2.3.1
2
7
 
3
8
  * Fixed backwards compatibility of strategies controller. The incompatibility was introduced in 2.3.0. (@jcoyne)
data/Gemfile CHANGED
@@ -15,7 +15,7 @@ group :test do
15
15
  gem "fakeredis", require: false
16
16
  gem "sqlite3", ">= 1.3", platform: :ruby
17
17
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby,
18
- github: "jruby/activerecord-jdbc-adapter", branch: "rails-5"
18
+ github: "jruby/activerecord-jdbc-adapter"
19
19
 
20
20
  gem "minitest", ">= 4.2"
21
21
  gem "capybara", ">= 2.6"
data/README.md CHANGED
@@ -78,6 +78,11 @@ end
78
78
  This file is automatically reloaded in development mode. No need to restart
79
79
  your server after making changes.
80
80
 
81
+ Feature definitions support these options:
82
+ * `:default` – The feature's default value. This is the value of the feature if no strategy configures an explicit value. Defaults to `false`.
83
+ * `:description` – An optional description of the feature. Displayed on the dashboard if present.
84
+ * `:title` – An optional title of the feature. This defaults to a humanized version of the feature name. Displayed on the dashboard.
85
+
81
86
  ## Strategies
82
87
 
83
88
  The following strategies are provided:
@@ -3,12 +3,12 @@ module Flipflop
3
3
  include ActionController::RequestForgeryProtection
4
4
 
5
5
  def update
6
- strategy.switch!(feature_key, enable?)
6
+ FeatureSet.current.switch!(feature_key, strategy_key, enable?)
7
7
  redirect_to(features_url)
8
8
  end
9
9
 
10
10
  def destroy
11
- strategy.clear!(feature_key)
11
+ FeatureSet.current.clear!(feature_key, strategy_key)
12
12
  redirect_to(features_url)
13
13
  end
14
14
 
@@ -27,8 +27,8 @@ module Flipflop
27
27
  params[:feature_id].to_sym
28
28
  end
29
29
 
30
- def strategy
31
- FeatureSet.current.strategy(params[:id])
30
+ def strategy_key
31
+ params[:id]
32
32
  end
33
33
  end
34
34
  end
@@ -1,14 +1,19 @@
1
1
  module Flipflop
2
2
  class FeatureDefinition
3
- attr_reader :key, :name, :title, :description, :default, :group
3
+ attr_reader :key, :name, :title, :description, :default, :group, :location
4
4
 
5
5
  def initialize(key, **options)
6
6
  @key = key
7
7
  @name = @key.to_s.freeze
8
- @title = @name.humanize.freeze
8
+ @title = options.delete(:title).freeze || @name.humanize.freeze
9
9
  @description = options.delete(:description).freeze
10
10
  @default = !!options.delete(:default) || false
11
11
  @group = options.delete(:group).freeze
12
+ @location = caller_locations(3, 1).first.freeze
13
+
14
+ if options.any?
15
+ raise FeatureError.new(name, "has unknown option #{options.keys.map(&:inspect) * ', '}")
16
+ end
12
17
  end
13
18
  end
14
19
  end
@@ -1,13 +1,19 @@
1
1
  module Flipflop
2
2
  class FeatureError < StandardError
3
- def initialize(feature, error)
4
- super("Feature '#{feature}' #{error}.")
3
+ def initialize(key, error)
4
+ super("Feature '#{key}' #{error}.")
5
5
  end
6
6
  end
7
7
 
8
8
  class StrategyError < StandardError
9
- def initialize(strategy, error)
10
- super("Strategy '#{strategy}' #{error}.")
9
+ def initialize(key, error)
10
+ super("Strategy '#{key}' #{error}.")
11
+ end
12
+ end
13
+
14
+ class Callback < StandardError
15
+ def initialize(key, error)
16
+ super("Callback '#{key}' #{error}.")
11
17
  end
12
18
  end
13
19
 
@@ -70,19 +76,22 @@ module Flipflop
70
76
  end
71
77
  end
72
78
 
73
- def enabled?(feature)
74
- FeatureCache.current.fetch(feature) do
79
+ def enabled?(feature_key)
80
+ FeatureCache.current.fetch(feature_key) do
81
+ feature = feature(feature_key)
82
+
75
83
  result = @strategies.each_value.inject(nil) do |status, strategy|
76
84
  break status unless status.nil?
77
- strategy.enabled?(feature)
85
+ strategy.enabled?(feature_key)
78
86
  end
79
- result.nil? ? feature(feature).default : result
87
+
88
+ result.nil? ? feature.default : result
80
89
  end
81
90
  end
82
91
 
83
- def feature(feature)
84
- @features.fetch(feature) do
85
- raise FeatureError.new(feature, "unknown")
92
+ def feature(feature_key)
93
+ @features.fetch(feature_key) do
94
+ raise FeatureError.new(feature_key, "unknown")
86
95
  end
87
96
  end
88
97
 
@@ -90,14 +99,28 @@ module Flipflop
90
99
  @features.values
91
100
  end
92
101
 
93
- def strategy(strategy)
94
- @strategies.fetch(strategy) do
95
- raise StrategyError.new(strategy, "unknown")
102
+ def strategy(strategy_key)
103
+ @strategies.fetch(strategy_key) do
104
+ raise StrategyError.new(strategy_key, "unknown")
96
105
  end
97
106
  end
98
107
 
99
108
  def strategies
100
109
  @strategies.values
101
110
  end
111
+
112
+ def switch!(feature_key, strategy_key, value)
113
+ strategy = strategy(strategy_key)
114
+ feature = feature(feature_key)
115
+
116
+ strategy.switch!(feature.key, value)
117
+ end
118
+
119
+ def clear!(feature_key, strategy_key)
120
+ strategy = strategy(strategy_key)
121
+ feature = feature(feature_key)
122
+
123
+ strategy.clear!(feature.key)
124
+ end
102
125
  end
103
126
  end
@@ -1,3 +1,3 @@
1
1
  module Flipflop
2
- VERSION = "2.3.1"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -10,26 +10,27 @@ class Flipflop::InstallGenerator < Rails::Generators::Base
10
10
  end
11
11
 
12
12
  def configure_dashboard
13
- comment = <<-RUBY
14
- # Replace with a lambda or method name defined in ApplicationController
15
- # to implement access control for the Flipflop dashboard.
16
- RUBY
17
-
18
- forbidden = <<-RUBY
19
- config.flipflop.dashboard_access_filter = -> { head :forbidden }
20
- RUBY
21
-
22
- allowed = <<-RUBY
23
- config.flipflop.dashboard_access_filter = nil
24
- RUBY
13
+ app = tmpl("-> { head :forbidden }")
14
+ env_dev_test = tmpl("nil")
25
15
 
26
- environment(indent(comment + forbidden + "\n", 4).lstrip)
27
- environment(indent(comment + allowed + "\n", 2).lstrip, env: [:development, :test])
16
+ environment(indent(app + "\n", 4).lstrip)
17
+ environment(indent(env_dev_test + "\n", 2).lstrip, env: [:development, :test])
28
18
  end
29
19
 
30
20
  private
31
21
 
22
+ def tmpl(access_filter)
23
+ return <<-RUBY
24
+ # Before filter for Flipflop dashboard. Replace with a lambda or method name
25
+ # defined in ApplicationController to implement access control.
26
+ config.flipflop.dashboard_access_filter = #{access_filter}
27
+ RUBY
28
+ end
29
+
32
30
  def indent(content, multiplier = 2)
31
+ # Don't fix indentation if Rails already does this (5.2+).
32
+ return content if respond_to?(:optimize_indentation, true)
33
+
33
34
  spaces = " " * multiplier
34
35
  content.each_line.map {|line| line.blank? ? line : "#{spaces}#{line}" }.join
35
36
  end
@@ -14,6 +14,23 @@ describe Flipflop do
14
14
  @app
15
15
  end
16
16
 
17
+ describe "configuration" do
18
+ it "should be added to dev" do
19
+ assert_match %r{^ config\.flipflop\.dashboard_access_filter = nil$},
20
+ File.read("config/environments/development.rb")
21
+ end
22
+
23
+ it "should be added to test" do
24
+ assert_match %r{^ config\.flipflop\.dashboard_access_filter = nil$},
25
+ File.read("config/environments/test.rb")
26
+ end
27
+
28
+ it "should be added to app" do
29
+ assert_match %r{^ config\.flipflop\.dashboard_access_filter = -> \{ head :forbidden \}$},
30
+ File.read("config/application.rb")
31
+ end
32
+ end
33
+
17
34
  describe "middleware" do
18
35
  it "should include cache middleware" do
19
36
  middlewares = Rails.application.middleware.map(&:klass)
data/test/test_helper.rb CHANGED
@@ -110,6 +110,10 @@ class TestApp
110
110
  skip_turbolinks: true,
111
111
  ).invoke_all
112
112
 
113
+ # Remove bootsnap if present, this interferes with reloading apps.
114
+ boot_path = File.expand_path("../../" + path + "/config/boot.rb", __FILE__)
115
+ File.write(boot_path, File.read(boot_path).gsub("require 'bootsnap/setup'", ""))
116
+
113
117
  Flipflop::InstallGenerator.new([],
114
118
  quiet: true,
115
119
  ).invoke_all
@@ -141,7 +145,13 @@ class TestApp
141
145
 
142
146
  silence_stdout { ActiveRecord::Tasks::DatabaseTasks.create_current }
143
147
  ActiveRecord::Migration.verbose = false
144
- ActiveRecord::Migrator.migrate(Rails.application.paths["db/migrate"].to_a)
148
+
149
+ if defined?(ActiveRecord::Migrator.migrate)
150
+ ActiveRecord::Migrator.migrate(Rails.application.paths["db/migrate"].to_a)
151
+ else
152
+ # Rails 5.2+
153
+ ActiveRecord::MigrationContext.new(Rails.application.paths["db/migrate"]).migrate
154
+ end
145
155
  end
146
156
 
147
157
  def unload!
@@ -29,6 +29,11 @@ describe Flipflop::FeatureDefinition do
29
29
  it "should have no group" do
30
30
  assert_nil subject.group
31
31
  end
32
+
33
+ it "should have location" do
34
+ # Because we have no indirection via FeatureSet, the location is minitest.
35
+ assert_equal "instance_eval", subject.location.label
36
+ end
32
37
  end
33
38
 
34
39
  describe "with options" do
@@ -63,5 +68,26 @@ describe Flipflop::FeatureDefinition do
63
68
  it "should have specified group" do
64
69
  assert_equal :my_group, subject.group.key
65
70
  end
71
+
72
+ it "should have location" do
73
+ # Because we have no indirection via FeatureSet, the location is minitest.
74
+ assert_equal "instance_eval", subject.location.label
75
+ end
76
+ end
77
+
78
+ describe "with unknown options" do
79
+ subject do
80
+ Flipflop::FeatureDefinition.new(:my_key,
81
+ unknown: "one",
82
+ other: "two",
83
+ )
84
+ end
85
+
86
+ it "should raise error with message" do
87
+ error = assert_raises Flipflop::FeatureError do
88
+ subject
89
+ end
90
+ assert_equal "Feature 'my_key' has unknown option :unknown, :other.", error.message
91
+ end
66
92
  end
67
93
  end
@@ -51,7 +51,13 @@ describe Flipflop::Strategies::AbstractStrategy do
51
51
  it "should raise if request is missing in thread" do
52
52
  Flipflop::Strategies::AbstractStrategy::RequestInterceptor.request = 3
53
53
  assert_raises Flipflop::StrategyError do
54
- Thread.new { subject.send(:request) }.value
54
+ Thread.new {
55
+ if Thread.current.respond_to?(:report_on_exception)
56
+ Thread.current.report_on_exception = false
57
+ end
58
+
59
+ subject.send(:request)
60
+ }.value
55
61
  end
56
62
  end
57
63
  end
@@ -1,6 +1,14 @@
1
1
  require File.expand_path("../../test_helper", __FILE__)
2
2
 
3
3
  describe "Flipflop::StrategiesController" do
4
+ before do
5
+ @app = TestApp.new
6
+ end
7
+
8
+ after do
9
+ @app.unload!
10
+ end
11
+
4
12
  subject do
5
13
  Flipflop::StrategiesController.new
6
14
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipflop
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Annesley
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-03-24 00:00:00.000000000 Z
13
+ date: 2018-04-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -82,8 +82,6 @@ files:
82
82
  - lib/generators/flipflop/migration/templates/create_features.rb
83
83
  - lib/generators/flipflop/routes/USAGE
84
84
  - lib/generators/flipflop/routes/routes_generator.rb
85
- - lib/test_engine/config/features.rb
86
- - lib/test_engine/test_engine.rb
87
85
  - src/stylesheets/_flipflop.scss
88
86
  - test/integration/app_test.rb
89
87
  - test/integration/dashboard_test.rb
@@ -130,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
128
  version: '0'
131
129
  requirements: []
132
130
  rubyforge_project:
133
- rubygems_version: 2.4.5
131
+ rubygems_version: 2.7.6
134
132
  signing_key:
135
133
  specification_version: 4
136
134
  summary: A feature flipflopper for Rails web applications.
@@ -1,3 +0,0 @@
1
- Flipflop.configure do
2
- feature :engine_feature
3
- end
@@ -1,7 +0,0 @@
1
- class TestEngine < Rails::Engine
2
- config.root = "lib/test_engine"
3
-
4
- initializer "features" do
5
- Flipflop::FeatureLoader.current.append(self)
6
- end
7
- end