arturo 1.0.0 → 1.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.
- data/README.md +33 -42
- data/app/controllers/arturo/features_controller.rb +3 -1
- data/lib/arturo.rb +1 -1
- data/lib/arturo/controller_filters.rb +1 -1
- data/lib/arturo/engine.rb +1 -0
- data/lib/arturo/feature_availability.rb +10 -2
- data/lib/arturo/feature_management.rb +23 -0
- data/lib/generators/arturo/templates/initializer.rb +18 -10
- metadata +4 -4
- data/lib/arturo/configuration.rb +0 -43
data/README.md
CHANGED
@@ -48,7 +48,7 @@ the feature:
|
|
48
48
|
|
49
49
|
# in app/controllers/postings_controller:
|
50
50
|
class PostingsController < ApplicationController
|
51
|
-
require_feature
|
51
|
+
require_feature :live_postings, :only => :recent
|
52
52
|
# ...
|
53
53
|
end
|
54
54
|
|
@@ -92,13 +92,17 @@ checkout.
|
|
92
92
|
|
93
93
|
### In Rails
|
94
94
|
|
95
|
-
#### Run the
|
95
|
+
#### Run the generators:
|
96
96
|
|
97
97
|
$ rails g arturo:migration
|
98
98
|
$ rails g arturo:initializer
|
99
99
|
$ rails g arturo:route
|
100
100
|
$ rails g arturo:assets
|
101
101
|
|
102
|
+
#### Run the migration:
|
103
|
+
|
104
|
+
$ rake db:migrate
|
105
|
+
|
102
106
|
#### Edit the configuration
|
103
107
|
|
104
108
|
##### Initializer
|
@@ -106,10 +110,10 @@ checkout.
|
|
106
110
|
Open up the newly-generated `config/initializers/arturo_initializer.rb`.
|
107
111
|
There are configuration options for the following:
|
108
112
|
|
109
|
-
* the
|
113
|
+
* the method that determines whether a user has permission to manage features
|
110
114
|
(see [admin permissions](#adminpermissions))
|
111
|
-
* the
|
112
|
-
(
|
115
|
+
* the method that returns the object that has features
|
116
|
+
(e.g. User, Person, or Account; see
|
113
117
|
[feature recipients](#featurerecipients))
|
114
118
|
* whitelists and blacklists for features
|
115
119
|
(see [white- and blacklisting](#wblisting))
|
@@ -132,20 +136,19 @@ work with you on support for your favorite framework.
|
|
132
136
|
|
133
137
|
### <span id='adminpermissions'>Admin Permissions</span>
|
134
138
|
|
135
|
-
`Arturo
|
136
|
-
a Controller instance. It should return `true`
|
137
|
-
|
138
|
-
|
139
|
-
might be
|
139
|
+
`Arturo::FeatureManagement#may_manage_features?` is a method that is run in
|
140
|
+
the context of a Controller or View instance. It should return `true` if
|
141
|
+
and only if the current user may manage permissions. The default implementation
|
142
|
+
is as follows:
|
140
143
|
|
141
|
-
|
142
|
-
current_user.admin?
|
143
|
-
end
|
144
|
+
current_user.present? && current_user.admin?
|
144
145
|
|
145
|
-
|
146
|
+
You can change the implementation in
|
147
|
+
`config/initializers/arturo_initializer.rb`. A reasonable implementation
|
148
|
+
might be
|
146
149
|
|
147
150
|
Arturo.permit_management do
|
148
|
-
signed_in? &&
|
151
|
+
signed_in? && current_user.can?(:manage_features)
|
149
152
|
end
|
150
153
|
|
151
154
|
### <span id='featurerecipients'>Feature Recipients</span>
|
@@ -157,35 +160,23 @@ early days -- may have deployed features on a per-university basis. It wouldn't
|
|
157
160
|
make much sense to deploy a feature to one user of a Basecamp project but not
|
158
161
|
to others, so 37Signals would probably want a per-project or per-account basis.
|
159
162
|
|
160
|
-
`Arturo
|
161
|
-
|
162
|
-
...) that is a member of the category that is the basis for
|
163
|
-
features.
|
164
|
-
`config/initializers/arturo_initializer.rb`. It should return an `Object` that
|
165
|
-
responds to `#id`. If you want to deploy features on a per-user basis, a
|
166
|
-
reasonable implementation might be
|
167
|
-
|
168
|
-
Arturo.thing_that_has_features do
|
169
|
-
current_user
|
170
|
-
end
|
171
|
-
|
172
|
-
or
|
173
|
-
|
174
|
-
Arturo.thing_that_has_features do
|
175
|
-
signed_in_person
|
176
|
-
end
|
163
|
+
`Arturo::FeatureAvailability#feature_recipient` is intended to support these
|
164
|
+
many use cases. It is a method that returns the current "thing" (a user, account,
|
165
|
+
project, university, ...) that is a member of the category that is the basis for
|
166
|
+
deploying new features. It should return an `Object` that responds to `#id`.
|
177
167
|
|
178
|
-
|
179
|
-
|
180
|
-
|
168
|
+
The default implementation simply returns `current_user`. Like
|
169
|
+
`Arturo::FeatureManagement#may_manage_features?`, this method can be configured
|
170
|
+
in `config/initializers/arturo_initializer.rb`. If you want to deploy features
|
171
|
+
on a per-account basis, a reasonable implementation might be
|
181
172
|
|
182
|
-
Arturo.
|
173
|
+
Arturo.feature_recipient do
|
183
174
|
current_account
|
184
175
|
end
|
185
176
|
|
186
177
|
or
|
187
178
|
|
188
|
-
Arturo.
|
179
|
+
Arturo.feature_recipient do
|
189
180
|
current_user.account
|
190
181
|
end
|
191
182
|
|
@@ -224,10 +215,10 @@ every action within `BookHoldsController` that is invoked by a user who
|
|
224
215
|
does not have the `:hold_book` feature.
|
225
216
|
|
226
217
|
class BookHoldsController < ApplicationController
|
227
|
-
require_feature
|
218
|
+
require_feature :hold_book
|
228
219
|
end
|
229
220
|
|
230
|
-
`require_feature
|
221
|
+
`require_feature` accepts as a second argument a `Hash` that it passes on
|
231
222
|
to `before_filter`, so you can use `:only` and `:except` to specify exactly
|
232
223
|
which actions are filtered.
|
233
224
|
|
@@ -258,11 +249,11 @@ The latter can be used like so:
|
|
258
249
|
|
259
250
|
**Note**: Arturo does not yet have caching support. Be very careful when
|
260
251
|
caching actions or pages that involve feature detection as you will get
|
261
|
-
strange behavior when a
|
252
|
+
strange behavior when a user who has access to a feature requests a page
|
262
253
|
just after one who does not (and vice versa). The following is the
|
263
254
|
**intended** support for caching.
|
264
255
|
|
265
|
-
Both the `require_feature
|
256
|
+
Both the `require_feature` before filter and the `if_feature_enabled` block
|
266
257
|
evaluation automatically append a string based on the feature's
|
267
258
|
`last_modified` timestamp to cache keys that Rails generates. Thus, you don't
|
268
259
|
have to worry about expiring caches when you increase a feature's deployment
|
@@ -272,4 +263,4 @@ percentage. See `Arturo::CacheSupport` for more information.
|
|
272
263
|
|
273
264
|
Arturo gets its name from
|
274
265
|
[Professor Maximillian Arturo](http://en.wikipedia.org/wiki/Maximillian_Arturo)
|
275
|
-
on [Sliders](http://en.wikipedia.org/wiki/Sliders).
|
266
|
+
on [Sliders](http://en.wikipedia.org/wiki/Sliders).
|
@@ -17,6 +17,8 @@ module Arturo
|
|
17
17
|
# should redefine Arturo::FeaturesController#permitted? to
|
18
18
|
# return true only for users who are permitted to manage features.
|
19
19
|
class FeaturesController < base
|
20
|
+
include Arturo::FeatureManagement
|
21
|
+
|
20
22
|
unloadable
|
21
23
|
respond_to :html, :json, :xml
|
22
24
|
before_filter :require_permission
|
@@ -95,7 +97,7 @@ module Arturo
|
|
95
97
|
protected
|
96
98
|
|
97
99
|
def require_permission
|
98
|
-
unless
|
100
|
+
unless may_manage_features?
|
99
101
|
render :action => 'forbidden', :status => 403
|
100
102
|
return false
|
101
103
|
end
|
data/lib/arturo.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Arturo
|
2
2
|
|
3
|
-
require 'arturo/configuration'
|
4
3
|
require 'arturo/special_handling'
|
5
4
|
require 'arturo/feature_availability'
|
5
|
+
require 'arturo/feature_management'
|
6
6
|
require 'arturo/controller_filters'
|
7
7
|
require 'arturo/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
8
8
|
|
data/lib/arturo/engine.rb
CHANGED
@@ -12,8 +12,7 @@ module Arturo
|
|
12
12
|
def feature_enabled?(symbol_or_feature)
|
13
13
|
feature = ::Arturo::Feature.to_feature(symbol_or_feature)
|
14
14
|
return false if feature.blank?
|
15
|
-
|
16
|
-
feature.enabled_for?(thing)
|
15
|
+
feature.enabled_for?(feature_recipient)
|
17
16
|
end
|
18
17
|
|
19
18
|
def if_feature_enabled(symbol_or_feature, &block)
|
@@ -24,6 +23,15 @@ module Arturo
|
|
24
23
|
end
|
25
24
|
end
|
26
25
|
|
26
|
+
# By default, returns current_user.
|
27
|
+
#
|
28
|
+
# If you would like to change this implementation, it is recommended
|
29
|
+
# you do so in config/initializers/arturo_initializer.rb
|
30
|
+
# @return [Object] the recipient of features.
|
31
|
+
def feature_recipient
|
32
|
+
current_user
|
33
|
+
end
|
34
|
+
|
27
35
|
end
|
28
36
|
|
29
37
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Arturo
|
2
|
+
|
3
|
+
# A mixin that is included by Arturo::FeaturesController and is declared
|
4
|
+
# as a helper for all views. It provides a single method,
|
5
|
+
# may_manage_features?, that returns whether or not the current user
|
6
|
+
# may manage features. By default, it is implemented as follows:
|
7
|
+
#
|
8
|
+
# def may_manage_features?
|
9
|
+
# current_user.present? && current_user.admin?
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# If you would like to change this implementation, it is recommended
|
13
|
+
# you do so in config/initializers/arturo_initializer.rb
|
14
|
+
module FeatureManagement
|
15
|
+
|
16
|
+
# @return [true,false] whether the current user may manage features
|
17
|
+
def may_manage_features?
|
18
|
+
current_user.present? && current_user.admin?
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -1,21 +1,29 @@
|
|
1
1
|
require 'arturo'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# Configure who may manage features here.
|
4
|
+
# The following is the default implementation.
|
5
|
+
# Arturo::FeatureManagement.class_eval do
|
6
|
+
# def may_manage_features?
|
7
|
+
# current_user.present? && current_user.admin?
|
8
|
+
# end
|
9
|
+
# end
|
6
10
|
|
7
|
-
|
8
|
-
|
9
|
-
|
11
|
+
# Configure what receives features here.
|
12
|
+
# The following is the default implementation.
|
13
|
+
# Arturo::FeatureAvailability.class_eval do
|
14
|
+
# def feature_recipient
|
15
|
+
# current_user
|
16
|
+
# end
|
17
|
+
# end
|
10
18
|
|
11
19
|
# Whitelists and Blacklists:
|
12
20
|
#
|
13
|
-
#
|
14
|
-
# Arturo::Feature.whitelist(
|
21
|
+
# Enable feature one for all admins:
|
22
|
+
# Arturo::Feature.whitelist(:feature_one) do |user|
|
15
23
|
# user.admin?
|
16
24
|
# end
|
17
25
|
#
|
18
|
-
#
|
19
|
-
# Arturo::Feature.blacklist(
|
26
|
+
# Disable feature two for all small accounts:
|
27
|
+
# Arturo::Feature.blacklist(:feature_two) do |user|
|
20
28
|
# user.account.small?
|
21
29
|
# end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 1.0.0
|
9
|
+
version: 1.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- James A. Rosen
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-10-
|
17
|
+
date: 2010-10-25 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -108,11 +108,11 @@ extensions: []
|
|
108
108
|
extra_rdoc_files: []
|
109
109
|
|
110
110
|
files:
|
111
|
-
- lib/arturo/configuration.rb
|
112
111
|
- lib/arturo/controller_filters.rb
|
113
112
|
- lib/arturo/engine.rb
|
114
113
|
- lib/arturo/feature_availability.rb
|
115
114
|
- lib/arturo/feature_factories.rb
|
115
|
+
- lib/arturo/feature_management.rb
|
116
116
|
- lib/arturo/special_handling.rb
|
117
117
|
- lib/arturo.rb
|
118
118
|
- lib/generators/arturo/assets_generator.rb
|
data/lib/arturo/configuration.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/module'
|
2
|
-
|
3
|
-
module Arturo
|
4
|
-
|
5
|
-
# A block that, when bound to a Controller instance, returns
|
6
|
-
# true iff the current user can manage features.
|
7
|
-
mattr_writer :permit_management
|
8
|
-
@@permit_management = lambda { false }
|
9
|
-
|
10
|
-
# A block that, when bound to a Controller or Helper instance,
|
11
|
-
# returns an object (probably a User, Person, or Account),
|
12
|
-
# that may or may not have features enabled.
|
13
|
-
mattr_writer :feature_recipient
|
14
|
-
@@feature_recipient = lambda { nil }
|
15
|
-
|
16
|
-
# Get or set Arturo's permission block.
|
17
|
-
# @param [block] block
|
18
|
-
# @return [block]
|
19
|
-
# @see Arturo.permission_block
|
20
|
-
def self.permit_management(&block)
|
21
|
-
if block
|
22
|
-
@@permit_management = block
|
23
|
-
end
|
24
|
-
@@permit_management
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.permit_management?(controller)
|
28
|
-
block = self.permit_management
|
29
|
-
block && block.call(controller)
|
30
|
-
end
|
31
|
-
|
32
|
-
# Get or set Arturo's block for retrieving the
|
33
|
-
# thing that may or may not have features enabled.
|
34
|
-
# @param [block] block
|
35
|
-
# @return [block]
|
36
|
-
def self.feature_recipient(&block)
|
37
|
-
if block
|
38
|
-
@@feature_recipient = block
|
39
|
-
end
|
40
|
-
@@feature_recipient
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|