plug 0.1.23 → 0.1.25
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 +4 -4
- data/README.md +1 -1
- data/Rakefile +3 -1
- data/app/assets/javascripts/plug/application.js +0 -2
- data/app/controllers/plug/api/api_controller.rb +2 -0
- data/app/controllers/plug/api/site_notices_controller.rb +2 -0
- data/app/controllers/plug/application_controller.rb +3 -3
- data/app/controllers/plug/features_controller.rb +13 -19
- data/app/controllers/plug/site_notices_controller.rb +13 -19
- data/app/helpers/plug/application_helper.rb +2 -0
- data/app/mailers/plug/application_mailer.rb +2 -0
- data/app/models/plug/application_record.rb +2 -0
- data/app/models/plug/concerns/model_helpers.rb +6 -5
- data/app/models/plug/feature.rb +2 -0
- data/app/models/plug/resources/site_notice.rb +2 -0
- data/app/models/plug/site_notice.rb +2 -0
- data/app/services/plug/task_execution_service.rb +2 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20180424015828_add_theme_to_plug_site_notice.rb +2 -0
- data/lib/generators/plug/install_generator.rb +3 -1
- data/lib/plug/configuration.rb +11 -9
- data/lib/plug/constraint.rb +4 -2
- data/lib/plug/engine.rb +4 -1
- data/lib/plug/version.rb +3 -1
- data/lib/plug.rb +15 -13
- data/lib/tasks/plug_tasks.rake +1 -0
- metadata +27 -43
- data/app/assets/javascripts/plug/features.js +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 887214bb19f4ba2255374fb542b912c43932f1d0aefdc6a4e2c3235957fbf6fd
|
4
|
+
data.tar.gz: ae3217d9d07a8ad3bbf57f3f84c86bd50fa78eab23583850a014850e3049862b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 389e71cfb8b619d007e164b0ed967ad1c79a2824a85c77c7b8e983d08f4c812a8cecd2ebcf09a8f350887da147c8b9409ac888397410a694edcf11ef72303b9e
|
7
|
+
data.tar.gz: be0c9b7483d6d9d6a019daaa1aaf60a97b92d70dbcf1c7df26e22cb5ec79f642e0fb2663f8d5ce94c5650e20766484737214181302b66d648442eb2b9f42177c
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Plug [](https://codeclimate.com/github/DigitalNZ/plug/maintainability)
|
1
|
+
# Plug [](https://codeclimate.com/github/DigitalNZ/plug/maintainability)
|
2
2
|
|
3
3
|
A Rails engine to turn on/off features (Feature flipper).
|
4
4
|
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'bundler/setup'
|
3
5
|
rescue LoadError
|
@@ -14,7 +16,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
14
16
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
17
|
end
|
16
18
|
|
17
|
-
APP_RAKEFILE = File.expand_path('
|
19
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
18
20
|
load 'rails/tasks/engine.rake'
|
19
21
|
|
20
22
|
load 'rails/tasks/statistics.rake'
|
@@ -1,11 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Plug
|
2
4
|
class ApplicationController < ActionController::Base
|
3
5
|
protect_from_forgery with: :exception
|
4
6
|
|
5
7
|
content_security_policy false
|
6
8
|
|
7
|
-
if Plug.auth_user.present? && Plug.auth_password.present?
|
8
|
-
http_basic_authenticate_with name: Plug.auth_user, password: Plug.auth_password
|
9
|
-
end
|
9
|
+
http_basic_authenticate_with name: Plug.auth_user, password: Plug.auth_password if Plug.auth_user.present? && Plug.auth_password.present?
|
10
10
|
end
|
11
11
|
end
|
@@ -1,12 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_dependency 'plug/application_controller'
|
2
4
|
|
3
5
|
module Plug
|
4
6
|
class FeaturesController < ApplicationController
|
5
|
-
|
6
|
-
before_filter :set_feature, only: [:edit, :update, :destroy]
|
7
|
-
else
|
8
|
-
before_action :set_feature, only: [:edit, :update, :destroy]
|
9
|
-
end
|
7
|
+
before_action :set_feature, only: %i[edit update destroy]
|
10
8
|
|
11
9
|
# GET /features
|
12
10
|
def index
|
@@ -37,7 +35,7 @@ module Plug
|
|
37
35
|
|
38
36
|
# PATCH/PUT /features/1
|
39
37
|
def update
|
40
|
-
if @feature.
|
38
|
+
if @feature.update(feature_params)
|
41
39
|
redirect_to features_path, notice: 'Feature was successfully updated.'
|
42
40
|
else
|
43
41
|
render :edit
|
@@ -65,19 +63,15 @@ module Plug
|
|
65
63
|
end
|
66
64
|
|
67
65
|
private
|
68
|
-
# Use callbacks to share common setup or constraints between actions.
|
69
|
-
def set_feature
|
70
|
-
@feature = Feature.find(params[:id])
|
71
|
-
end
|
72
66
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
67
|
+
# Use callbacks to share common setup or constraints between actions.
|
68
|
+
def set_feature
|
69
|
+
@feature = Feature.find(params[:id])
|
70
|
+
end
|
71
|
+
|
72
|
+
# Only allow a trusted parameter "white list" through.
|
73
|
+
def feature_params
|
74
|
+
params.require(:feature).permit(:name, :description, :state, :notice)
|
75
|
+
end
|
82
76
|
end
|
83
77
|
end
|
@@ -1,12 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_dependency 'plug/application_controller'
|
2
4
|
|
3
5
|
module Plug
|
4
6
|
class SiteNoticesController < ApplicationController
|
5
|
-
|
6
|
-
before_filter :set_site_notice, only: [:edit, :update, :destroy]
|
7
|
-
else
|
8
|
-
before_action :set_site_notice, only: [:edit, :update, :destroy]
|
9
|
-
end
|
7
|
+
before_action :set_site_notice, only: %i[edit update destroy]
|
10
8
|
|
11
9
|
# GET /site_notices
|
12
10
|
def index
|
@@ -37,7 +35,7 @@ module Plug
|
|
37
35
|
|
38
36
|
# PATCH/PUT /site_notices/1
|
39
37
|
def update
|
40
|
-
if @site_notice.
|
38
|
+
if @site_notice.update(site_notice_params)
|
41
39
|
redirect_to site_notices_path, notice: 'Site Notice was successfully updated.'
|
42
40
|
else
|
43
41
|
render :edit
|
@@ -51,19 +49,15 @@ module Plug
|
|
51
49
|
end
|
52
50
|
|
53
51
|
private
|
54
|
-
# Use callbacks to share common setup or constraints between actions.
|
55
|
-
def set_site_notice
|
56
|
-
@site_notice = SiteNotice.find(params[:id])
|
57
|
-
end
|
58
52
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
53
|
+
# Use callbacks to share common setup or constraints between actions.
|
54
|
+
def set_site_notice
|
55
|
+
@site_notice = SiteNotice.find(params[:id])
|
56
|
+
end
|
57
|
+
|
58
|
+
# Only allow a trusted parameter "white list" through.
|
59
|
+
def site_notice_params
|
60
|
+
params.require(:site_notice).permit(:name, :notice, :state, :theme)
|
61
|
+
end
|
68
62
|
end
|
69
63
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Plug
|
@@ -9,9 +11,9 @@ module Plug
|
|
9
11
|
include AASM
|
10
12
|
|
11
13
|
# Validations
|
12
|
-
validates :name, presence: { message: "#{
|
13
|
-
uniqueness: { message: "#{
|
14
|
-
validates :state, presence: { message: "#{
|
14
|
+
validates :name, presence: { message: "#{humanized_class_name} name is required" },
|
15
|
+
uniqueness: { message: "#{humanized_class_name} name must be unique", case_sensitive: false }
|
16
|
+
validates :state, presence: { message: "#{humanized_class_name} state is required" }
|
15
17
|
|
16
18
|
# Callbacks
|
17
19
|
before_save { self.slug = name.parameterize }
|
@@ -32,12 +34,11 @@ module Plug
|
|
32
34
|
transitions from: :enabled, to: :disabled
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
36
37
|
end
|
37
38
|
|
38
39
|
module ClassMethods
|
39
40
|
def humanized_class_name
|
40
|
-
|
41
|
+
name.demodulize.underscore.humanize.capitalize
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
data/app/models/plug/feature.rb
CHANGED
data/config/routes.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Plug
|
2
4
|
class InstallGenerator < Rails::Generators::Base
|
3
|
-
source_root File.expand_path('
|
5
|
+
source_root File.expand_path('templates', __dir__)
|
4
6
|
|
5
7
|
def copy_initializer_file
|
6
8
|
copy_file 'plug.rb', 'config/initializers/plug.rb'
|
data/lib/plug/configuration.rb
CHANGED
@@ -1,26 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Plug
|
2
4
|
module Configuration
|
3
5
|
AUTH_USER = ''
|
4
6
|
AUTH_PASSWORD = ''
|
5
7
|
ALLOW_DELETE = true
|
6
8
|
|
7
|
-
VALID_OPTIONS_KEYS = [
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
VALID_OPTIONS_KEYS = %i[
|
10
|
+
auth_user
|
11
|
+
auth_password
|
12
|
+
allow_delete
|
13
|
+
buttons
|
14
|
+
api_path
|
15
|
+
themes
|
14
16
|
].freeze
|
15
17
|
|
16
|
-
attr_accessor
|
18
|
+
attr_accessor(*VALID_OPTIONS_KEYS)
|
17
19
|
|
18
20
|
def configure
|
19
21
|
yield self
|
20
22
|
end
|
21
23
|
|
22
24
|
def options
|
23
|
-
Hash[
|
25
|
+
Hash[* VALID_OPTIONS_KEYS.map { |key| [key, send(key)] }.flatten]
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
data/lib/plug/constraint.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Plug
|
2
4
|
class Constraint
|
3
5
|
def initialize(feature)
|
4
6
|
@feature = feature
|
5
7
|
end
|
6
8
|
|
7
|
-
def matches?(
|
9
|
+
def matches?(_request)
|
8
10
|
Plug.enabled?(@feature)
|
9
|
-
rescue
|
11
|
+
rescue StandardError
|
10
12
|
true
|
11
13
|
end
|
12
14
|
end
|
data/lib/plug/engine.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Require engine dependencies
|
2
4
|
require 'haml-rails'
|
3
5
|
require 'aasm'
|
4
|
-
require 'jquery-rails'
|
5
6
|
|
6
7
|
module Plug
|
7
8
|
class Engine < ::Rails::Engine
|
@@ -9,6 +10,8 @@ module Plug
|
|
9
10
|
|
10
11
|
config.generators do |g|
|
11
12
|
g.test_framework :rspec
|
13
|
+
g.fixture_replacement :factory_bot
|
14
|
+
g.factory_bot dir: 'spec/factories'
|
12
15
|
end
|
13
16
|
end
|
14
17
|
end
|
data/lib/plug/version.rb
CHANGED
data/lib/plug.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'plug/engine'
|
2
4
|
require 'plug/configuration'
|
3
5
|
require 'plug/constraint'
|
@@ -12,9 +14,9 @@ module Plug
|
|
12
14
|
#
|
13
15
|
# @return [Boolean] true - Feature found and enabled | true - Feature not found (We don't want to block) | false - Feature was set to disabled
|
14
16
|
def enabled?(arg)
|
15
|
-
|
16
|
-
rescue
|
17
|
-
|
17
|
+
get_feature(arg).enabled?
|
18
|
+
rescue StandardError
|
19
|
+
true
|
18
20
|
end
|
19
21
|
|
20
22
|
#
|
@@ -27,21 +29,21 @@ module Plug
|
|
27
29
|
feature = get_feature(arg)
|
28
30
|
|
29
31
|
render_notice(feature.notice, &block) unless feature.enabled? || feature.notice.blank?
|
30
|
-
rescue
|
31
|
-
|
32
|
+
rescue StandardError
|
33
|
+
nil
|
32
34
|
end
|
33
35
|
|
34
36
|
private
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
+
def get_feature(arg)
|
39
|
+
arg = arg.to_s if arg.is_a? Symbol
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
+
return Plug::Feature.slug_and_name(arg).first
|
42
|
+
end
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
+
def render_notice(notice, &block)
|
45
|
+
return notice unless block_given?
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
+
yield(notice)
|
48
|
+
end
|
47
49
|
end
|
data/lib/tasks/plug_tasks.rake
CHANGED
metadata
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.25
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- Ben
|
8
7
|
- Boost
|
9
|
-
|
8
|
+
- DNZ
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-07-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: aasm
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: activeresource
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
43
|
+
name: haml-rails
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - ">="
|
@@ -54,21 +54,21 @@ dependencies:
|
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
57
|
+
name: rails
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
62
|
+
version: '5.2'
|
63
63
|
type: :runtime
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
69
|
+
version: '5.2'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
71
|
+
name: sass-rails
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
74
|
- - ">="
|
@@ -82,13 +82,13 @@ dependencies:
|
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
|
-
name:
|
85
|
+
name: capybara
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
88
|
- - ">="
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: '0'
|
91
|
-
type: :
|
91
|
+
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
@@ -96,7 +96,7 @@ dependencies:
|
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '0'
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
|
-
name:
|
99
|
+
name: factory_bot_rails
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
102
|
- - ">="
|
@@ -109,36 +109,22 @@ dependencies:
|
|
109
109
|
- - ">="
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0'
|
112
|
-
- !ruby/object:Gem::Dependency
|
113
|
-
name: rspec-rails
|
114
|
-
requirement: !ruby/object:Gem::Requirement
|
115
|
-
requirements:
|
116
|
-
- - "~>"
|
117
|
-
- !ruby/object:Gem::Version
|
118
|
-
version: 3.7.1
|
119
|
-
type: :development
|
120
|
-
prerelease: false
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
122
|
-
requirements:
|
123
|
-
- - "~>"
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: 3.7.1
|
126
112
|
- !ruby/object:Gem::Dependency
|
127
113
|
name: rails-controller-testing
|
128
114
|
requirement: !ruby/object:Gem::Requirement
|
129
115
|
requirements:
|
130
|
-
- - "
|
116
|
+
- - ">="
|
131
117
|
- !ruby/object:Gem::Version
|
132
|
-
version:
|
118
|
+
version: '0'
|
133
119
|
type: :development
|
134
120
|
prerelease: false
|
135
121
|
version_requirements: !ruby/object:Gem::Requirement
|
136
122
|
requirements:
|
137
|
-
- - "
|
123
|
+
- - ">="
|
138
124
|
- !ruby/object:Gem::Version
|
139
|
-
version:
|
125
|
+
version: '0'
|
140
126
|
- !ruby/object:Gem::Dependency
|
141
|
-
name:
|
127
|
+
name: rspec-rails
|
142
128
|
requirement: !ruby/object:Gem::Requirement
|
143
129
|
requirements:
|
144
130
|
- - ">="
|
@@ -152,7 +138,7 @@ dependencies:
|
|
152
138
|
- !ruby/object:Gem::Version
|
153
139
|
version: '0'
|
154
140
|
- !ruby/object:Gem::Dependency
|
155
|
-
name:
|
141
|
+
name: selenium-webdriver
|
156
142
|
requirement: !ruby/object:Gem::Requirement
|
157
143
|
requirements:
|
158
144
|
- - ">="
|
@@ -166,7 +152,7 @@ dependencies:
|
|
166
152
|
- !ruby/object:Gem::Version
|
167
153
|
version: '0'
|
168
154
|
- !ruby/object:Gem::Dependency
|
169
|
-
name:
|
155
|
+
name: shoulda-matchers
|
170
156
|
requirement: !ruby/object:Gem::Requirement
|
171
157
|
requirements:
|
172
158
|
- - ">="
|
@@ -180,7 +166,7 @@ dependencies:
|
|
180
166
|
- !ruby/object:Gem::Version
|
181
167
|
version: '0'
|
182
168
|
- !ruby/object:Gem::Dependency
|
183
|
-
name:
|
169
|
+
name: sqlite3
|
184
170
|
requirement: !ruby/object:Gem::Requirement
|
185
171
|
requirements:
|
186
172
|
- - ">="
|
@@ -193,9 +179,8 @@ dependencies:
|
|
193
179
|
- - ">="
|
194
180
|
- !ruby/object:Gem::Version
|
195
181
|
version: '0'
|
196
|
-
description: Rails engine that can plug/unplug features with notice
|
182
|
+
description: Rails engine that can plug/unplug features with notice
|
197
183
|
email:
|
198
|
-
- benedict@boost.co.nz
|
199
184
|
- info@boost.co.nz
|
200
185
|
executables: []
|
201
186
|
extensions: []
|
@@ -207,7 +192,6 @@ files:
|
|
207
192
|
- app/assets/config/plug_manifest.js
|
208
193
|
- app/assets/images/favicon.png
|
209
194
|
- app/assets/javascripts/plug/application.js
|
210
|
-
- app/assets/javascripts/plug/features.js
|
211
195
|
- app/assets/javascripts/plug/trix-core.js
|
212
196
|
- app/assets/stylesheets/plug/_settings.scss
|
213
197
|
- app/assets/stylesheets/plug/application.scss
|
@@ -267,11 +251,11 @@ files:
|
|
267
251
|
- lib/plug/engine.rb
|
268
252
|
- lib/plug/version.rb
|
269
253
|
- lib/tasks/plug_tasks.rake
|
270
|
-
homepage: https://github.com/
|
254
|
+
homepage: https://github.com/digitalnz/plug
|
271
255
|
licenses:
|
272
256
|
- MIT
|
273
257
|
metadata: {}
|
274
|
-
post_install_message:
|
258
|
+
post_install_message:
|
275
259
|
rdoc_options: []
|
276
260
|
require_paths:
|
277
261
|
- lib
|
@@ -286,8 +270,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
286
270
|
- !ruby/object:Gem::Version
|
287
271
|
version: '0'
|
288
272
|
requirements: []
|
289
|
-
rubygems_version: 3.
|
290
|
-
signing_key:
|
273
|
+
rubygems_version: 3.2.32
|
274
|
+
signing_key:
|
291
275
|
specification_version: 4
|
292
276
|
summary: Rails engine that can plug/unplug features
|
293
277
|
test_files: []
|