feature_creep 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +13 -4
- data/lib/feature_creep.rb +36 -64
- data/lib/feature_creep/default_config.rb +36 -0
- data/lib/feature_creep/version.rb +1 -1
- data/spec/feature_creep_spec.rb +3 -1
- data/spec/spec_helper.rb +1 -0
- metadata +3 -2
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -11,14 +11,23 @@ This is not a drop in replacement. The API has aleadey changed.
|
|
11
11
|
Namely, `groups` are now `scopes` and `users` are `agent_ids`.
|
12
12
|
Agent_ids are expected to be uuids, not the object itself.
|
13
13
|
|
14
|
-
The class constructor now takes
|
14
|
+
The class constructor now takes
|
15
15
|
|
16
|
-
|
16
|
+
`datastore` -- FeatureCreep::RedisDatastore is provided with more to come.
|
17
17
|
|
18
|
-
|
18
|
+
`info` -- should be a lambda that takes two parameters and returns a hash when called
|
19
19
|
|
20
|
-
|
20
|
+
`warden` -- is also a lambda that takes two parameters and returns a boolean. It encapsulates the business logic for FeatureCreep#active?
|
21
21
|
|
22
|
+
`options` -- an aptly named options hash
|
23
|
+
|
24
|
+
`options[:scopes]` is a hash that expects a string key and a lambda that encapsulates the business logic for membership in a scope
|
25
|
+
|
26
|
+
`options[:features]` is an array of strings or symbols that will add to the list of all possible features.
|
27
|
+
|
28
|
+
@feature_creep = FeatureCreep.new(@datastore,FeatureCreep::DefaultConfig.warden,
|
29
|
+
FeatureCreep::DefaultConfig.info,
|
30
|
+
{:scopes => {:some_scope_name => lambda { |agent_id| User.find(agent_id).can?(:some_scope) }}, :features => [:feature_1, :feature_2]})
|
22
31
|
|
23
32
|
At this point it should be easy to extend.
|
24
33
|
I would expect the API to stablize over the next couple of weeks.
|
data/lib/feature_creep.rb
CHANGED
@@ -2,8 +2,10 @@ class FeatureCreep
|
|
2
2
|
|
3
3
|
attr_accessor :scopes, :info, :warden
|
4
4
|
|
5
|
-
def initialize(datastore, options = {})
|
5
|
+
def initialize(datastore, warden, info, options = {})
|
6
6
|
@datastore = datastore
|
7
|
+
@warden = warden
|
8
|
+
@info = info
|
7
9
|
@scopes = {"all" => lambda { |agent_id| true }}
|
8
10
|
|
9
11
|
if options.has_key?(:scopes)
|
@@ -17,95 +19,47 @@ class FeatureCreep
|
|
17
19
|
add_feature(feature)
|
18
20
|
end
|
19
21
|
end
|
20
|
-
|
21
|
-
@warden = if options.has_key?(:warden)
|
22
|
-
options[:warden]
|
23
|
-
else
|
24
|
-
lambda { |feature,agent_id|
|
25
|
-
if agent_id
|
26
|
-
active_globally?(feature) ||
|
27
|
-
agent_id_in_active_scope?(feature, agent_id) ||
|
28
|
-
agent_id_active?(feature, agent_id) ||
|
29
|
-
agent_id_within_active_percentage?(feature, agent_id)
|
30
|
-
else
|
31
|
-
active_globally?(feature)
|
32
|
-
end
|
33
|
-
}
|
34
|
-
end
|
35
|
-
|
36
|
-
@info = if options.has_key?(:info)
|
37
|
-
options[:info]
|
38
|
-
else lambda { |feature|
|
39
|
-
if feature
|
40
|
-
{
|
41
|
-
:percentage => (active_percentage(feature) || 0).to_i,
|
42
|
-
:scopes => active_scopes(feature).map { |g| g.to_sym },
|
43
|
-
:agent_ids => active_agent_ids(feature),
|
44
|
-
:global => active_global_features,
|
45
|
-
:available_features => features
|
46
|
-
}
|
47
|
-
else
|
48
|
-
{
|
49
|
-
:global => active_global_features,
|
50
|
-
:available_features => features
|
51
|
-
}
|
52
|
-
end
|
53
|
-
}
|
54
|
-
end
|
55
22
|
end
|
56
23
|
|
24
|
+
# Activate Methods
|
57
25
|
def activate_globally(feature)
|
58
26
|
@datastore.activate_globally(feature)
|
59
27
|
end
|
60
28
|
|
61
|
-
def deactivate_globally(feature)
|
62
|
-
@datastore.deactivate_globally(feature)
|
63
|
-
end
|
64
|
-
|
65
29
|
def activate_scope(feature, scope)
|
66
30
|
@datastore.activate_scope(feature, scope)
|
67
31
|
end
|
68
32
|
|
69
|
-
def deactivate_scope(feature, scope)
|
70
|
-
@datastore.deactivate_scope(feature, scope)
|
71
|
-
end
|
72
|
-
|
73
|
-
def deactivate_all(feature)
|
74
|
-
@datastore.deactivate_all(feature)
|
75
|
-
end
|
76
|
-
|
77
33
|
def activate_agent_id(feature, agent_id)
|
78
34
|
@datastore.activate_agent_id(feature, agent_id)
|
79
35
|
end
|
80
36
|
|
81
|
-
def deactivate_agent_id(feature, agent_id)
|
82
|
-
@datastore.deactivate_agent_id(feature, agent_id)
|
83
|
-
end
|
84
|
-
|
85
|
-
def active?(feature, agent_id = nil)
|
86
|
-
@warden.call(feature,agent_id)
|
87
|
-
end
|
88
|
-
|
89
37
|
def activate_percentage(feature, percentage)
|
90
38
|
@datastore.activate_percentage(feature, percentage)
|
91
39
|
end
|
92
40
|
|
93
|
-
|
94
|
-
|
41
|
+
# Deactivate Methods
|
42
|
+
def deactivate_globally(feature)
|
43
|
+
@datastore.deactivate_globally(feature)
|
95
44
|
end
|
96
45
|
|
97
|
-
def
|
98
|
-
@datastore.
|
46
|
+
def deactivate_scope(feature, scope)
|
47
|
+
@datastore.deactivate_scope(feature, scope)
|
99
48
|
end
|
100
49
|
|
101
|
-
def
|
102
|
-
@datastore.
|
50
|
+
def deactivate_agent_id(feature, agent_id)
|
51
|
+
@datastore.deactivate_agent_id(feature, agent_id)
|
103
52
|
end
|
104
53
|
|
105
|
-
def
|
106
|
-
@
|
54
|
+
def deactivate_percentage(feature)
|
55
|
+
@datastore.deactivate_percentage(feature)
|
56
|
+
end
|
57
|
+
|
58
|
+
def deactivate_all(feature)
|
59
|
+
@datastore.deactivate_all(feature)
|
107
60
|
end
|
108
61
|
|
62
|
+
# Reporting Methods
|
109
63
|
def active_scopes(feature)
|
110
64
|
@datastore.active_scopes(feature)
|
111
65
|
end
|
@@ -122,6 +76,11 @@ class FeatureCreep
|
|
122
76
|
@datastore.active_percentage(feature)
|
123
77
|
end
|
124
78
|
|
79
|
+
# Boolean Methods
|
80
|
+
def active?(feature, agent_id = nil)
|
81
|
+
@warden.call(self,feature,agent_id)
|
82
|
+
end
|
83
|
+
|
125
84
|
def active_globally?(feature)
|
126
85
|
@datastore.active_globally?(feature)
|
127
86
|
end
|
@@ -139,4 +98,17 @@ class FeatureCreep
|
|
139
98
|
def agent_id_within_active_percentage?(feature, agent_id)
|
140
99
|
@datastore.agent_id_within_active_percentage?(feature, agent_id)
|
141
100
|
end
|
101
|
+
|
102
|
+
# Utility Methods
|
103
|
+
def features
|
104
|
+
@datastore.features
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_feature(feature)
|
108
|
+
@datastore.add_feature(feature)
|
109
|
+
end
|
110
|
+
|
111
|
+
def info(feature = nil)
|
112
|
+
@info.call(self,feature)
|
113
|
+
end
|
142
114
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class FeatureCreep
|
2
|
+
class DefaultConfig
|
3
|
+
def self.info
|
4
|
+
lambda { |creep,feature|
|
5
|
+
if feature
|
6
|
+
{
|
7
|
+
:percentage => (creep.active_percentage(feature) || 0).to_i,
|
8
|
+
:scopes => creep.active_scopes(feature).map { |g| g.to_sym },
|
9
|
+
:agent_ids => creep.active_agent_ids(feature),
|
10
|
+
:global => creep.active_global_features,
|
11
|
+
:available_features => creep.features
|
12
|
+
}
|
13
|
+
else
|
14
|
+
{
|
15
|
+
:global => creep.active_global_features,
|
16
|
+
:available_features => creep.features
|
17
|
+
}
|
18
|
+
end
|
19
|
+
}
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.warden
|
24
|
+
lambda { |creep,feature,agent_id|
|
25
|
+
if agent_id
|
26
|
+
creep.active_globally?(feature) ||
|
27
|
+
creep.agent_id_in_active_scope?(feature, agent_id) ||
|
28
|
+
creep.agent_id_active?(feature, agent_id) ||
|
29
|
+
creep.agent_id_within_active_percentage?(feature, agent_id)
|
30
|
+
else
|
31
|
+
creep.active_globally?(feature)
|
32
|
+
end
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/feature_creep_spec.rb
CHANGED
@@ -6,7 +6,9 @@ describe "FeatureCreep" do
|
|
6
6
|
scopes = {
|
7
7
|
:fivesonly => lambda { |agent_id| agent_id == 5 }
|
8
8
|
}
|
9
|
-
@feature_creep = FeatureCreep.new(@datastore,
|
9
|
+
@feature_creep = FeatureCreep.new(@datastore,FeatureCreep::DefaultConfig.warden,
|
10
|
+
FeatureCreep::DefaultConfig.info,
|
11
|
+
{:scopes => scopes, :features => [:test1, :test2]})
|
10
12
|
end
|
11
13
|
|
12
14
|
describe ".new" do
|
data/spec/spec_helper.rb
CHANGED
@@ -2,6 +2,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
2
2
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
3
|
require 'feature_creep'
|
4
4
|
require 'feature_creep/redis_datastore'
|
5
|
+
require 'feature_creep/default_config'
|
5
6
|
require 'rspec'
|
6
7
|
require 'bourne'
|
7
8
|
require 'redis'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feature_creep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -137,6 +137,7 @@ files:
|
|
137
137
|
- README.md
|
138
138
|
- feature_creep.gemspec
|
139
139
|
- lib/feature_creep.rb
|
140
|
+
- lib/feature_creep/default_config.rb
|
140
141
|
- lib/feature_creep/redis_datastore.rb
|
141
142
|
- lib/feature_creep/version.rb
|
142
143
|
- spec/feature_creep_spec.rb
|