feature_creep 0.1.2 → 0.2.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/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
|