rails_flags 0.1.0 → 0.1.1

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
  SHA256:
3
- metadata.gz: fd89ec7b4bef50b03eeda197bffb23d1f88da83dfd91e7e68d18f65643b46c46
4
- data.tar.gz: b3fe66c98c53b2f07e10460a08d8853f4e2f62d79ca37f20eb2b66c2d453a6ea
3
+ metadata.gz: fe7b819caaddc037424b3b33e788af96fa02da82f94c6ec2b60c7fe99431e886
4
+ data.tar.gz: d68835ff9af94c371e65bc0d4b35386d67f9e749cb61a7818dfc7e8abc0900d8
5
5
  SHA512:
6
- metadata.gz: 39f075f0e4bd50afffcb40f53a6130b535151c0e8cfcf1f60dc3bc265ef82e84b2393ca2457cfe54dc7b1a32728501593cc792267c3d0269e121cd3032ecc7c5
7
- data.tar.gz: 3da159ab062c096037bda7c92a38696fd987c6fde0209dc5206885e3f71bc22f13cbf8a6f9d5c5f00649b28d3d6a976c1c52ecf692037b5400c8fb957b9c1c2a
6
+ metadata.gz: 2b9893919d8d482e8c2b9b0ecebde2dbdd2c0c62fffc9597962e9aeb89ce9cb74eb6d1a988e98d7aa67cb8ff55446fa6987d4b48821a2c50116d3ebf4a9335f1
7
+ data.tar.gz: 30c12444f5b1d0464e8a4e479cb648e8ecc3910574faa68700bd47393de218ff4f3912cd44ad022e46e889187ed88609be4d08f05977decf0f1f272eafed9821
data/README.md CHANGED
@@ -9,6 +9,7 @@ A simple and powerful feature flagging system for Ruby on Rails applications. Ra
9
9
  - Thread-safe operations
10
10
  - Configurable default states
11
11
  - Support for flag metadata (descriptions, creation timestamps)
12
+ - Built-in admin interface for managing feature flags
12
13
 
13
14
  ## Installation
14
15
 
@@ -46,7 +47,28 @@ RailsFlags.configure do |config|
46
47
  end
47
48
  ```
48
49
 
49
- ### Registering Flags
50
+ ## Usage
51
+
52
+ ### Mounting the Engine
53
+ Add this to your `config/routes.rb`:
54
+ ```ruby
55
+ Rails.application.routes.draw do
56
+ mount RailsFlags::Engine => "/rails_flags"
57
+ end
58
+ ```
59
+
60
+ ### Admin Interface
61
+ Access the admin interface at `/rails_flags/admin` to:
62
+ - View all feature flags
63
+ - Create new feature flags
64
+ - Enable/disable flags
65
+ - Delete feature flags
66
+
67
+ ![RailsFlags](docs/images/dashboard.png)
68
+
69
+ ### Programmatic Usage
70
+
71
+ #### Registering Flags
50
72
  ```ruby
51
73
  # Register a new feature flag (disabled by default)
52
74
  RailsFlags.register(
@@ -63,7 +85,7 @@ RailsFlags.register(
63
85
  )
64
86
  ```
65
87
 
66
- ### Checking Flags
88
+ #### Checking Flags
67
89
  ```ruby
68
90
  # Check if a flag is enabled
69
91
  if RailsFlags.enabled?(:new_feature)
@@ -74,7 +96,7 @@ end
74
96
  RailsFlags.registered?(:new_feature)
75
97
  ```
76
98
 
77
- ### Managing Flags
99
+ #### Managing Flags
78
100
  ```ruby
79
101
  # Enable a flag
80
102
  RailsFlags.enable(:new_feature)
@@ -82,10 +104,21 @@ RailsFlags.enable(:new_feature)
82
104
  # Disable a flag
83
105
  RailsFlags.disable(:new_feature)
84
106
 
107
+ # Delete a flag
108
+ RailsFlags.delete(:new_feature)
109
+
85
110
  # Get all flags
86
111
  all_flags = RailsFlags.all_flags
87
112
  ```
88
113
 
114
+ ### In Views
115
+ You can use feature flags in your views:
116
+ ```erb
117
+ <% if RailsFlags.enabled?(:new_feature) %>
118
+ <!-- New feature content -->
119
+ <% end %>
120
+ ```
121
+
89
122
  ## Storage Adapters
90
123
 
91
124
  ### Memory Adapter
@@ -99,6 +132,23 @@ all_flags = RailsFlags.all_flags
99
132
  - Provides atomic operations
100
133
  - Requires Redis server
101
134
 
135
+ ## Testing
136
+
137
+ This gem supports multiple Rails versions (6.x, 7.x, and 8.x). We use Appraisal to test against different Rails versions.
138
+
139
+ To run the tests for all supported Rails versions:
140
+
141
+ ```bash
142
+ bundle exec appraisal rspec
143
+ ```
144
+
145
+ To run tests for a specific Rails version:
146
+
147
+ ```bash
148
+ bundle exec appraisal rails-6 rspec # For Rails 6
149
+ bundle exec appraisal rails-7 rspec # For Rails 7
150
+ bundle exec appraisal rails-8 rspec # For Rails 8
151
+ ```
102
152
 
103
153
  ## Contributing
104
154
 
@@ -0,0 +1,36 @@
1
+ module RailsFlags
2
+ class AdminController < ApplicationController
3
+ def index
4
+ @feature_flags = RailsFlags.all_flags
5
+ end
6
+
7
+ def create
8
+ RailsFlags.register(
9
+ params[:name],
10
+ enabled: params[:enabled] == "1",
11
+ description: params[:description]
12
+ )
13
+ redirect_to admin_path, notice: "Feature flag created successfully"
14
+ rescue StandardError => e
15
+ redirect_to admin_path, alert: e.message
16
+ end
17
+
18
+ def update
19
+ if params[:enabled] == "1"
20
+ RailsFlags.enable(params[:name])
21
+ else
22
+ RailsFlags.disable(params[:name])
23
+ end
24
+ redirect_to admin_path, notice: "Feature flag updated successfully"
25
+ rescue StandardError => e
26
+ redirect_to admin_path, alert: e.message
27
+ end
28
+
29
+ def destroy
30
+ RailsFlags.delete(params[:name])
31
+ redirect_to admin_path, notice: "Feature flag deleted successfully"
32
+ rescue StandardError => e
33
+ redirect_to admin_path, alert: e.message
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,101 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Feature Flags Admin</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+
9
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
10
+ </head>
11
+ <body>
12
+ <div class="container mt-4">
13
+ <h1>Feature Flags Admin</h1>
14
+
15
+ <% if notice %>
16
+ <div class="alert alert-success"><%= notice %></div>
17
+ <% end %>
18
+
19
+ <% if alert %>
20
+ <div class="alert alert-danger"><%= alert %></div>
21
+ <% end %>
22
+
23
+ <!-- New Feature Flag Form -->
24
+ <div class="card mb-4">
25
+ <div class="card-header">
26
+ <h5 class="mb-0">Create New Feature Flag</h5>
27
+ </div>
28
+ <div class="card-body">
29
+ <%= form_tag admin_create_path, method: :post, class: 'row g-3' do %>
30
+ <div class="col-md-4">
31
+ <label class="form-label">Name</label>
32
+ <%= text_field_tag :name, nil, class: 'form-control', required: true %>
33
+ </div>
34
+ <div class="col-md-6">
35
+ <label class="form-label">Description</label>
36
+ <%= text_field_tag :description, nil, class: 'form-control' %>
37
+ </div>
38
+ <div class="col-md-2">
39
+ <label class="form-label">Enabled</label>
40
+ <div>
41
+ <%= check_box_tag :enabled, "1", false, class: 'form-check-input' %>
42
+ </div>
43
+ </div>
44
+ <div class="col-12">
45
+ <%= submit_tag 'Create Feature Flag', class: 'btn btn-primary' %>
46
+ </div>
47
+ <% end %>
48
+ </div>
49
+ </div>
50
+
51
+ <!-- Feature Flags List -->
52
+ <div class="card">
53
+ <div class="card-header">
54
+ <h5 class="mb-0">Existing Feature Flags</h5>
55
+ </div>
56
+ <div class="card-body">
57
+ <div class="table-responsive">
58
+ <table class="table">
59
+ <thead>
60
+ <tr>
61
+ <th>Name</th>
62
+ <th>Description</th>
63
+ <th>Status</th>
64
+ <th>Created At</th>
65
+ <th>Actions</th>
66
+ </tr>
67
+ </thead>
68
+ <tbody>
69
+ <% @feature_flags.each do |name, data| %>
70
+ <tr>
71
+ <td><%= name %></td>
72
+ <td><%= data[:description] %></td>
73
+ <td>
74
+ <%= form_tag admin_update_path(name), method: :patch, class: 'd-inline' do %>
75
+ <div class="form-check form-switch">
76
+ <%= check_box_tag :enabled, "1", data[:enabled],
77
+ class: 'form-check-input',
78
+ onchange: 'this.form.submit()' %>
79
+ </div>
80
+ <% end %>
81
+ </td>
82
+ <td><%= data[:created_at]&.strftime("%Y-%m-%d %H:%M:%S") %></td>
83
+ <td>
84
+ <%= button_to "Delete",
85
+ admin_delete_path(name),
86
+ method: :delete,
87
+ class: "btn btn-danger btn-sm",
88
+ data: { confirm: "Are you sure?" } %>
89
+ </td>
90
+ </tr>
91
+ <% end %>
92
+ </tbody>
93
+ </table>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+
99
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
100
+ </body>
101
+ </html>
data/config/routes.rb CHANGED
@@ -1,2 +1,8 @@
1
1
  RailsFlags::Engine.routes.draw do
2
+ get "/admin", to: "admin#index", as: :admin
3
+ post "/admin/create", to: "admin#create", as: :admin_create
4
+ patch "/admin/:name", to: "admin#update", as: :admin_update
5
+ delete "/admin/:name", to: "admin#destroy", as: :admin_delete
6
+
7
+ root to: "admin#index"
2
8
  end
@@ -42,6 +42,11 @@ module RailsFlags
42
42
  @adapter.write(flag.to_sym, data)
43
43
  end
44
44
 
45
+ def delete(flag)
46
+ validate_flag_exists!(flag)
47
+ @adapter.delete(flag.to_sym)
48
+ end
49
+
45
50
  def registered?(flag)
46
51
  @adapter.read(flag.to_sym) ? true : false
47
52
  end
@@ -53,7 +58,8 @@ module RailsFlags
53
58
  private
54
59
 
55
60
  def validate_flag_name!(name)
56
- raise ArgumentError, "Flag name must be a String or Symbol" unless name.is_a?(String) || name.is_a?(Symbol)
61
+ raise ArgumentError, "Flag name cannot be nil" if name.nil?
62
+ raise ArgumentError, "Flag name must be a string or symbol" unless name.is_a?(String) || name.is_a?(Symbol)
57
63
  raise ArgumentError, "Flag name cannot be empty" if name.to_s.strip.empty?
58
64
  end
59
65
 
@@ -1,3 +1,3 @@
1
1
  module RailsFlags
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/rails_flags.rb CHANGED
@@ -19,6 +19,10 @@ module RailsFlags
19
19
  configuration.register(flag_name, **options)
20
20
  end
21
21
 
22
+ def delete(flag_name)
23
+ configuration.delete(flag_name)
24
+ end
25
+
22
26
  def enabled?(flag)
23
27
  configuration.enabled?(flag)
24
28
  rescue KeyError => e
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_flags
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dhurba Baral
@@ -16,14 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 8.0.0
19
+ version: '6.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8.1'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: 8.0.0
29
+ version: '6.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8.1'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: redis
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +58,20 @@ dependencies:
52
58
  - - ">="
53
59
  - !ruby/object:Gem::Version
54
60
  version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: appraisal
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
55
75
  description: A simple and powerful feature flagging system for Ruby on Rails applications.
56
76
  RailsFlags provides an easy way to manage feature flags with support for multiple
57
77
  storage backends.
@@ -65,12 +85,14 @@ files:
65
85
  - README.md
66
86
  - Rakefile
67
87
  - app/assets/stylesheets/rails_flags/application.css
88
+ - app/controllers/rails_flags/admin_controller.rb
68
89
  - app/controllers/rails_flags/application_controller.rb
69
90
  - app/helpers/rails_flags/application_helper.rb
70
91
  - app/jobs/rails_flags/application_job.rb
71
92
  - app/mailers/rails_flags/application_mailer.rb
72
93
  - app/models/rails_flags/application_record.rb
73
94
  - app/views/layouts/rails_flags/application.html.erb
95
+ - app/views/rails_flags/admin/index.html.erb
74
96
  - config/routes.rb
75
97
  - lib/rails_flags.rb
76
98
  - lib/rails_flags/adapters/base.rb