beta_feature 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", ">= 6.0.0.rc1", "< 6.1"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,199 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ beta_feature (0.1.0)
5
+ rails (>= 4.2, < 6.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actioncable (6.0.2.2)
11
+ actionpack (= 6.0.2.2)
12
+ nio4r (~> 2.0)
13
+ websocket-driver (>= 0.6.1)
14
+ actionmailbox (6.0.2.2)
15
+ actionpack (= 6.0.2.2)
16
+ activejob (= 6.0.2.2)
17
+ activerecord (= 6.0.2.2)
18
+ activestorage (= 6.0.2.2)
19
+ activesupport (= 6.0.2.2)
20
+ mail (>= 2.7.1)
21
+ actionmailer (6.0.2.2)
22
+ actionpack (= 6.0.2.2)
23
+ actionview (= 6.0.2.2)
24
+ activejob (= 6.0.2.2)
25
+ mail (~> 2.5, >= 2.5.4)
26
+ rails-dom-testing (~> 2.0)
27
+ actionpack (6.0.2.2)
28
+ actionview (= 6.0.2.2)
29
+ activesupport (= 6.0.2.2)
30
+ rack (~> 2.0, >= 2.0.8)
31
+ rack-test (>= 0.6.3)
32
+ rails-dom-testing (~> 2.0)
33
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
34
+ actiontext (6.0.2.2)
35
+ actionpack (= 6.0.2.2)
36
+ activerecord (= 6.0.2.2)
37
+ activestorage (= 6.0.2.2)
38
+ activesupport (= 6.0.2.2)
39
+ nokogiri (>= 1.8.5)
40
+ actionview (6.0.2.2)
41
+ activesupport (= 6.0.2.2)
42
+ builder (~> 3.1)
43
+ erubi (~> 1.4)
44
+ rails-dom-testing (~> 2.0)
45
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
46
+ activejob (6.0.2.2)
47
+ activesupport (= 6.0.2.2)
48
+ globalid (>= 0.3.6)
49
+ activemodel (6.0.2.2)
50
+ activesupport (= 6.0.2.2)
51
+ activerecord (6.0.2.2)
52
+ activemodel (= 6.0.2.2)
53
+ activesupport (= 6.0.2.2)
54
+ activestorage (6.0.2.2)
55
+ actionpack (= 6.0.2.2)
56
+ activejob (= 6.0.2.2)
57
+ activerecord (= 6.0.2.2)
58
+ marcel (~> 0.3.1)
59
+ activesupport (6.0.2.2)
60
+ concurrent-ruby (~> 1.0, >= 1.0.2)
61
+ i18n (>= 0.7, < 2)
62
+ minitest (~> 5.1)
63
+ tzinfo (~> 1.1)
64
+ zeitwerk (~> 2.2)
65
+ appraisal (2.2.0)
66
+ bundler
67
+ rake
68
+ thor (>= 0.14.0)
69
+ ast (2.4.0)
70
+ builder (3.2.4)
71
+ coderay (1.1.2)
72
+ concurrent-ruby (1.1.6)
73
+ crass (1.0.6)
74
+ diff-lcs (1.3)
75
+ erubi (1.9.0)
76
+ globalid (0.4.2)
77
+ activesupport (>= 4.2.0)
78
+ i18n (1.8.2)
79
+ concurrent-ruby (~> 1.0)
80
+ jaro_winkler (1.5.4)
81
+ loofah (2.5.0)
82
+ crass (~> 1.0.2)
83
+ nokogiri (>= 1.5.9)
84
+ mail (2.7.1)
85
+ mini_mime (>= 0.1.1)
86
+ marcel (0.3.3)
87
+ mimemagic (~> 0.3.2)
88
+ method_source (1.0.0)
89
+ mimemagic (0.3.4)
90
+ mini_mime (1.0.2)
91
+ mini_portile2 (2.4.0)
92
+ minitest (5.14.0)
93
+ mysql2 (0.5.3)
94
+ nio4r (2.5.2)
95
+ nokogiri (1.10.9)
96
+ mini_portile2 (~> 2.4.0)
97
+ parallel (1.19.1)
98
+ parser (2.7.1.1)
99
+ ast (~> 2.4.0)
100
+ pg (1.2.3)
101
+ pry (0.13.1)
102
+ coderay (~> 1.1)
103
+ method_source (~> 1.0)
104
+ rack (2.2.2)
105
+ rack-test (1.1.0)
106
+ rack (>= 1.0, < 3)
107
+ rails (6.0.2.2)
108
+ actioncable (= 6.0.2.2)
109
+ actionmailbox (= 6.0.2.2)
110
+ actionmailer (= 6.0.2.2)
111
+ actionpack (= 6.0.2.2)
112
+ actiontext (= 6.0.2.2)
113
+ actionview (= 6.0.2.2)
114
+ activejob (= 6.0.2.2)
115
+ activemodel (= 6.0.2.2)
116
+ activerecord (= 6.0.2.2)
117
+ activestorage (= 6.0.2.2)
118
+ activesupport (= 6.0.2.2)
119
+ bundler (>= 1.3.0)
120
+ railties (= 6.0.2.2)
121
+ sprockets-rails (>= 2.0.0)
122
+ rails-dom-testing (2.0.3)
123
+ activesupport (>= 4.2.0)
124
+ nokogiri (>= 1.6)
125
+ rails-html-sanitizer (1.3.0)
126
+ loofah (~> 2.3)
127
+ railties (6.0.2.2)
128
+ actionpack (= 6.0.2.2)
129
+ activesupport (= 6.0.2.2)
130
+ method_source
131
+ rake (>= 0.8.7)
132
+ thor (>= 0.20.3, < 2.0)
133
+ rainbow (3.0.0)
134
+ rake (13.0.1)
135
+ rexml (3.2.4)
136
+ rspec (3.9.0)
137
+ rspec-core (~> 3.9.0)
138
+ rspec-expectations (~> 3.9.0)
139
+ rspec-mocks (~> 3.9.0)
140
+ rspec-core (3.9.1)
141
+ rspec-support (~> 3.9.1)
142
+ rspec-expectations (3.9.1)
143
+ diff-lcs (>= 1.2.0, < 2.0)
144
+ rspec-support (~> 3.9.0)
145
+ rspec-mocks (3.9.1)
146
+ diff-lcs (>= 1.2.0, < 2.0)
147
+ rspec-support (~> 3.9.0)
148
+ rspec-rails (3.9.0)
149
+ actionpack (>= 3.0)
150
+ activesupport (>= 3.0)
151
+ railties (>= 3.0)
152
+ rspec-core (~> 3.9.0)
153
+ rspec-expectations (~> 3.9.0)
154
+ rspec-mocks (~> 3.9.0)
155
+ rspec-support (~> 3.9.0)
156
+ rspec-support (3.9.2)
157
+ rubocop (0.82.0)
158
+ jaro_winkler (~> 1.5.1)
159
+ parallel (~> 1.10)
160
+ parser (>= 2.7.0.1)
161
+ rainbow (>= 2.2.2, < 4.0)
162
+ rexml
163
+ ruby-progressbar (~> 1.7)
164
+ unicode-display_width (>= 1.4.0, < 2.0)
165
+ ruby-progressbar (1.10.1)
166
+ sprockets (4.0.0)
167
+ concurrent-ruby (~> 1.0)
168
+ rack (> 1, < 3)
169
+ sprockets-rails (3.2.1)
170
+ actionpack (>= 4.0)
171
+ activesupport (>= 4.0)
172
+ sprockets (>= 3.0.0)
173
+ thor (1.0.1)
174
+ thread_safe (0.3.6)
175
+ tzinfo (1.2.7)
176
+ thread_safe (~> 0.1)
177
+ unicode-display_width (1.7.0)
178
+ websocket-driver (0.7.1)
179
+ websocket-extensions (>= 0.1.0)
180
+ websocket-extensions (0.1.4)
181
+ zeitwerk (2.3.0)
182
+
183
+ PLATFORMS
184
+ ruby
185
+
186
+ DEPENDENCIES
187
+ appraisal
188
+ beta_feature!
189
+ mysql2 (>= 0.3.20)
190
+ pg (>= 0.18, < 2.0)
191
+ pry
192
+ rails (>= 6.0.0.rc1, < 6.1)
193
+ rake (>= 12.3.3)
194
+ rspec (>= 3.0)
195
+ rspec-rails (>= 3.5)
196
+ rubocop (>= 0.54.0)
197
+
198
+ BUNDLED WITH
199
+ 1.17.3
@@ -0,0 +1,24 @@
1
+ require 'active_record'
2
+ require 'active_support'
3
+ require 'yaml'
4
+
5
+ require "beta_feature/version"
6
+ require "beta_feature/flagger"
7
+ require "beta_feature/setting"
8
+ require "beta_feature/error"
9
+
10
+ module BetaFeature
11
+ def self.all_betas
12
+ @@__all_betas__ ||= YAML.load_file("#{Rails.root}/config/beta_features.yml")
13
+ end
14
+
15
+ def self.in_progress
16
+ @@__in_progress_betas__ ||= all_betas.select {|k, v| v["status"] == 'in_progress'}
17
+ end
18
+
19
+ def self.released
20
+ @@__released_betas__ ||= all_betas.select {|k, v| v["status"] == 'released'}
21
+ end
22
+ end
23
+
24
+ ::ActiveRecord::Base.send :include, BetaFeature::Flagger
@@ -0,0 +1,4 @@
1
+ module BetaFeature
2
+ class Error < StandardError; end
3
+ class BetaNotDefined < Error; end
4
+ end
@@ -0,0 +1,70 @@
1
+ require 'set'
2
+
3
+ module BetaFeature
4
+
5
+ module Flagger
6
+ extend ::ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def flagger
10
+ return if included_modules.include?(::BetaFeature::Flagger::BetaFeatureInstanceMethods)
11
+
12
+ include ::BetaFeature::Flagger::BetaFeatureInstanceMethods
13
+
14
+ has_one :beta_feature_setting, class_name: "BetaFeature::Setting", as: :betable
15
+ end
16
+ end
17
+
18
+ module BetaFeatureInstanceMethods
19
+ def can_access_beta?(*betas)
20
+ betas = betas.map(&:to_s)
21
+ validate_beta_name(*betas)
22
+ betas.all? {|key| all_betas.include?(key) }
23
+ end
24
+
25
+ # add feature flags.
26
+ def enable_beta!(*betas)
27
+ betas = betas.map(&:to_s)
28
+ validate_beta_name(*betas)
29
+ betas = (find_or_create_beta_feature_setting.betas + betas).uniq
30
+ beta_feature_setting.update(betas: betas)
31
+
32
+ flush_beta_cache
33
+ end
34
+
35
+ #remove feature flags
36
+ def remove_beta!(*betas)
37
+ betas = betas.map(&:to_s)
38
+ validate_beta_name(*betas)
39
+
40
+ betas = (find_or_create_beta_feature_setting.betas - betas).uniq
41
+ beta_feature_setting.update(betas: betas)
42
+
43
+ flush_beta_cache
44
+ end
45
+
46
+ def all_betas
47
+ @__all_betas__ ||= find_or_create_beta_feature_setting.betas.to_set
48
+ end
49
+
50
+ private
51
+
52
+ def validate_beta_name(*betas)
53
+ betas.each do |beta|
54
+ if !BetaFeature.all_betas.key?(beta)
55
+ msg = "Please define #{beta} in config/beta_features.yml"
56
+ raise BetaFeature::BetaNotDefined.new(msg)
57
+ end
58
+ end
59
+ end
60
+
61
+ def find_or_create_beta_feature_setting
62
+ beta_feature_setting || create_beta_feature_setting
63
+ end
64
+
65
+ def flush_beta_cache
66
+ remove_instance_variable(:@__all_betas__) if defined? @__all_betas__
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module BetaFeature
3
+ class Setting < ::ActiveRecord::Base
4
+ self.table_name = "beta_feature_settings"
5
+
6
+ validates :betable_type, presence: true
7
+ validates :betable_id, presence: true, uniqueness: { scope: :betable_type }
8
+
9
+ belongs_to :betable, polymorphic: true
10
+
11
+
12
+ def clean_invalid_betas!
13
+ #TODO
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module BetaFeature
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'active_record'
4
+ require 'rails/generators/active_record'
5
+ require 'generators/beta_feature/migration'
6
+ require 'generators/beta_feature/migration_helper'
7
+
8
+
9
+ module BetaFeature
10
+ module Generators
11
+ class InstallGenerator < Rails::Generators::Base
12
+ include Rails::Generators::Migration
13
+ include BetaFeature::Generators::MigrationHelper
14
+ extend BetaFeature::Generators::Migration
15
+
16
+ source_root File.expand_path("../templates", __FILE__)
17
+
18
+ def copy_migrateion
19
+ migration_template 'install.rb', 'db/migrate/install_beta_feature.rb'
20
+ copy_file 'beta_features.yml', 'config/beta_features.yml'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module BetaFeature
2
+ module Generators
3
+ module Migration
4
+ # Implement the required interface for Rails::Generators::Migration.
5
+ def next_migration_number(dirname) #:nodoc:
6
+ next_migration_number = current_migration_number(dirname) + 1
7
+ if ::ActiveRecord::Base.timestamped_migrations
8
+ [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
9
+ else
10
+ "%.3d" % next_migration_number
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module BetaFeature
2
+ module Generators
3
+ module MigrationHelper
4
+ def migration_parent
5
+ if Rails::VERSION::MAJOR == 4
6
+ 'ActiveRecord::Migration'
7
+ else
8
+ "ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ landing_page_ux_improvement:
2
+ developer: 'ryan@corp.com'
3
+ qa: 'windy@corp.com'
4
+ status: 'in_progress'
5
+ description: 'This is a demo feature flag.'
6
+
7
+ dark_mode:
8
+ developer: 'max@corp.com'
9
+ qa: 'daniel@corp.com'
10
+ status: 'in_progress'
11
+ description: 'Build dark mode on our website.'
12
+
13
+ custom_domain:
14
+ developer: 'max@corp.com'
15
+ qa: 'daniel@corp.com'
16
+ status: released
17
+ description: 'Support custom domain for Pro user.'
18
+
@@ -0,0 +1,16 @@
1
+ class <%= migration_class_name %> < <%= migration_parent %>
2
+ def self.up
3
+ create_table :beta_feature_settings, force: true do |t|
4
+ t.integer :betable_id, null: false
5
+ t.string :betable_type, null: false
6
+ t.string :betas, array: true, default: [], null: false
7
+ t.timestamps
8
+
9
+ t.index [:betable_type, :betable_id], unique: true
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ drop_table :beta_feature_settings
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,217 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: beta_feature
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Lv
8
+ - Windy Liu
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2020-04-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '4.2'
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: '6.1'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: '4.2'
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '6.1'
34
+ - !ruby/object:Gem::Dependency
35
+ name: appraisal
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ type: :development
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec-rails
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.5'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '3.5'
76
+ - !ruby/object:Gem::Dependency
77
+ name: pry
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ - !ruby/object:Gem::Dependency
91
+ name: rake
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 12.3.3
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 12.3.3
104
+ - !ruby/object:Gem::Dependency
105
+ name: rubocop
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 0.54.0
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 0.54.0
118
+ - !ruby/object:Gem::Dependency
119
+ name: mysql2
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 0.3.20
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 0.3.20
132
+ - !ruby/object:Gem::Dependency
133
+ name: pg
134
+ requirement: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0.18'
139
+ - - "<"
140
+ - !ruby/object:Gem::Version
141
+ version: '2.0'
142
+ type: :development
143
+ prerelease: false
144
+ version_requirements: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0.18'
149
+ - - "<"
150
+ - !ruby/object:Gem::Version
151
+ version: '2.0'
152
+ description: Rails feature toggle for trunk based development.
153
+ email:
154
+ - tech@workstream.is
155
+ executables: []
156
+ extensions: []
157
+ extra_rdoc_files: []
158
+ files:
159
+ - ".gitignore"
160
+ - ".rspec"
161
+ - ".rubycop.yml"
162
+ - ".travis.yml"
163
+ - Appraisals
164
+ - CHANGELOG.md
165
+ - CODE_OF_CONDUCT.md
166
+ - Gemfile
167
+ - LICENSE.txt
168
+ - README.md
169
+ - Rakefile
170
+ - beta_feature.gemspec
171
+ - bin/console
172
+ - bin/setup
173
+ - gemfiles/rails50.gemfile
174
+ - gemfiles/rails50.gemfile.lock
175
+ - gemfiles/rails51.gemfile
176
+ - gemfiles/rails51.gemfile.lock
177
+ - gemfiles/rails52.gemfile
178
+ - gemfiles/rails52.gemfile.lock
179
+ - gemfiles/rails60.gemfile
180
+ - gemfiles/rails60.gemfile.lock
181
+ - lib/beta_feature.rb
182
+ - lib/beta_feature/error.rb
183
+ - lib/beta_feature/flagger.rb
184
+ - lib/beta_feature/setting.rb
185
+ - lib/beta_feature/version.rb
186
+ - lib/generators/beta_feature/install_generator.rb
187
+ - lib/generators/beta_feature/migration.rb
188
+ - lib/generators/beta_feature/migration_helper.rb
189
+ - lib/generators/beta_feature/templates/beta_features.yml
190
+ - lib/generators/beta_feature/templates/install.rb
191
+ homepage: https://github.com/helloworld1812/beta_feature
192
+ licenses:
193
+ - MIT
194
+ metadata:
195
+ homepage_uri: https://github.com/helloworld1812/beta_feature
196
+ source_code_uri: https://github.com/helloworld1812/beta_feature
197
+ changelog_uri: https://github.com/helloworld1812/beta_feature/blob/master/CHANGELOG.md
198
+ post_install_message:
199
+ rdoc_options: []
200
+ require_paths:
201
+ - lib
202
+ required_ruby_version: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: 2.3.0
207
+ required_rubygems_version: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - ">="
210
+ - !ruby/object:Gem::Version
211
+ version: '0'
212
+ requirements: []
213
+ rubygems_version: 3.0.6
214
+ signing_key:
215
+ specification_version: 4
216
+ summary: Rails feature toggle for trunk based development.
217
+ test_files: []