beta_feature 0.1.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.
@@ -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: []