feature_release 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/feature_release.gemspec +1 -0
- data/lib/feature_release.rb +20 -1
- data/lib/feature_release/feature.rb +13 -1
- data/lib/feature_release/storage.rb +42 -0
- data/lib/feature_release/version.rb +1 -1
- data/spec/feature_release_spec.rb +34 -0
- data/spec/feature_spec.rb +16 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/storage_spec.rb +34 -0
- metadata +23 -4
data/feature_release.gemspec
CHANGED
data/lib/feature_release.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
require "feature_release/version"
|
2
2
|
require "feature_release/feature"
|
3
|
+
require "feature_release/storage"
|
3
4
|
|
4
5
|
class FeatureRelease
|
5
6
|
|
6
7
|
attr_reader :groups, :features
|
7
8
|
|
8
|
-
def initialize
|
9
|
+
def initialize(storage=nil)
|
9
10
|
@groups = {:all => lambda{|obj| true}}
|
10
11
|
@features = Hash.new do |hash, missing_key|
|
11
12
|
hash[missing_key] = Feature.new(missing_key)
|
12
13
|
end
|
14
|
+
set_storage(storage) if storage
|
13
15
|
end
|
14
16
|
|
15
17
|
def define_group(name, &block)
|
@@ -29,4 +31,21 @@ class FeatureRelease
|
|
29
31
|
@features[feature.to_sym].groups.all? {|group| groups[group].call(user)}
|
30
32
|
end
|
31
33
|
|
34
|
+
def persisted?(feature)
|
35
|
+
!(@storage.get(@features[feature.to_sym].name).nil?)
|
36
|
+
end
|
37
|
+
|
38
|
+
def save
|
39
|
+
@features.each{|key, value| @storage.save(value.name, value.to_string)}
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def set_storage(storage)
|
45
|
+
@storage = storage
|
46
|
+
@storage.get_all.each do |feature_name|
|
47
|
+
@features[feature_name.to_sym] = Feature.new(feature_name, @storage.get(feature_name))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
32
51
|
end
|
@@ -3,10 +3,12 @@ class FeatureRelease
|
|
3
3
|
class Feature
|
4
4
|
|
5
5
|
attr_accessor :groups
|
6
|
+
attr_reader :name
|
6
7
|
|
7
|
-
def initialize(name)
|
8
|
+
def initialize(name, groups_string=nil)
|
8
9
|
@name = name
|
9
10
|
@groups = []
|
11
|
+
parse_groups(groups_string)
|
10
12
|
end
|
11
13
|
|
12
14
|
def add_group(group)
|
@@ -17,6 +19,16 @@ class FeatureRelease
|
|
17
19
|
@groups.delete(group.to_sym)
|
18
20
|
end
|
19
21
|
|
22
|
+
def to_string
|
23
|
+
@groups.join(",")
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def parse_groups(string)
|
28
|
+
return unless string
|
29
|
+
@groups = string.split(",").map(&:to_sym)
|
30
|
+
end
|
31
|
+
|
20
32
|
end
|
21
33
|
|
22
34
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class FeatureRelease
|
3
|
+
class Storage
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@store = options.fetch(:store)
|
7
|
+
end
|
8
|
+
|
9
|
+
def save(feature, data)
|
10
|
+
persist(feature, data)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(feature)
|
14
|
+
retrieve(feature_key(feature))
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_all
|
18
|
+
(retrieve(global_key) || "").split(",").map(&:to_sym)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def feature_key(feature)
|
25
|
+
"feature:#{feature}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def global_key
|
29
|
+
"features:all"
|
30
|
+
end
|
31
|
+
|
32
|
+
def persist(feature, data)
|
33
|
+
@store.set(feature_key(feature), data)
|
34
|
+
@store.set(global_key, (get_all | [feature]).join(","))
|
35
|
+
end
|
36
|
+
|
37
|
+
def retrieve(key)
|
38
|
+
@store.get(key)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -57,4 +57,38 @@ describe FeatureRelease do
|
|
57
57
|
|
58
58
|
end
|
59
59
|
|
60
|
+
context "persistence" do
|
61
|
+
let(:tester) {double("user", :new? => true, :admin? => false)}
|
62
|
+
let(:admin) {double("user", :admin? => true, :new? => false)}
|
63
|
+
|
64
|
+
before(:each) do
|
65
|
+
@redis = MockRedis.new
|
66
|
+
@storage = FeatureRelease::Storage.new(store:@redis)
|
67
|
+
@fr = FeatureRelease.new(@storage)
|
68
|
+
@fr.define_group(:testers) do |user|
|
69
|
+
user.new?
|
70
|
+
end
|
71
|
+
@fr.activate_feature(:test_feature, :testers)
|
72
|
+
@fr.define_group(:admins) do |user|
|
73
|
+
user.admin?
|
74
|
+
end
|
75
|
+
@fr.activate_feature(:new_feature, :admins)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "commands its storage object to save the features" do
|
79
|
+
@fr.save
|
80
|
+
@fr.persisted?(:test_feature).should be_true
|
81
|
+
end
|
82
|
+
|
83
|
+
it "can build itself from persisted date" do
|
84
|
+
@fr.save
|
85
|
+
@new_fr = FeatureRelease.new(@storage)
|
86
|
+
@new_fr.define_group(:admins) do |user|
|
87
|
+
user.admin?
|
88
|
+
end
|
89
|
+
@new_fr.active?(:new_feature, admin).should be_true
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
end
|
60
94
|
end
|
data/spec/feature_spec.rb
CHANGED
@@ -23,5 +23,21 @@ describe FeatureRelease::Feature do
|
|
23
23
|
f.remove_group(:testers)
|
24
24
|
f.groups.should_not include(:testers)
|
25
25
|
end
|
26
|
+
|
27
|
+
it "can be to_string into a string" do
|
28
|
+
f = FeatureRelease::Feature.new(:test_feature)
|
29
|
+
f.add_group(:testers)
|
30
|
+
f.add_group(:admins)
|
31
|
+
f.to_string.should eq("testers,admins")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can be built from a string" do
|
35
|
+
f = FeatureRelease::Feature.new(:test_feature)
|
36
|
+
f.add_group(:testers)
|
37
|
+
f.add_group(:admins)
|
38
|
+
string = f.to_string
|
39
|
+
from_s = FeatureRelease::Feature.new(:test_feature, string)
|
40
|
+
from_s.groups.should eq([:testers, :admins])
|
41
|
+
end
|
26
42
|
|
27
43
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FeatureRelease::Storage do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@redis = MockRedis.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should initialize with a store" do
|
10
|
+
expect{FeatureRelease::Storage.new()}.to raise_error
|
11
|
+
expect{FeatureRelease::Storage.new(store: @redis)}.to_not raise_error
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'saving features' do
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
@storage = FeatureRelease::Storage.new(store: @redis)
|
18
|
+
@feature = double 'Feature', name: :test_feature, to_string: "test_users, new_users, admin_users"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should save a feature to the store" do
|
22
|
+
@storage.save(@feature.name, @feature.to_string)
|
23
|
+
@storage.get(@feature.name).should eq(@feature.to_string)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should add a feature to the collection of features" do
|
27
|
+
@storage = FeatureRelease::Storage.new(store: @redis)
|
28
|
+
@storage.save(@feature.name, @feature.to_string)
|
29
|
+
@storage.get_all.should eq([:test_feature])
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feature_release
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
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: 2014-05-
|
12
|
+
date: 2014-05-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -59,6 +59,22 @@ dependencies:
|
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: mock_redis
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
62
78
|
description: Allows you to restrict access of portions of an app to certain users
|
63
79
|
email:
|
64
80
|
- kavinderd@gmail.com
|
@@ -75,10 +91,12 @@ files:
|
|
75
91
|
- feature_release.gemspec
|
76
92
|
- lib/feature_release.rb
|
77
93
|
- lib/feature_release/feature.rb
|
94
|
+
- lib/feature_release/storage.rb
|
78
95
|
- lib/feature_release/version.rb
|
79
96
|
- spec/feature_release_spec.rb
|
80
97
|
- spec/feature_spec.rb
|
81
98
|
- spec/spec_helper.rb
|
99
|
+
- spec/storage_spec.rb
|
82
100
|
homepage: ''
|
83
101
|
licenses:
|
84
102
|
- MIT
|
@@ -94,7 +112,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
112
|
version: '0'
|
95
113
|
segments:
|
96
114
|
- 0
|
97
|
-
hash:
|
115
|
+
hash: -1008631629134333472
|
98
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
117
|
none: false
|
100
118
|
requirements:
|
@@ -103,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
121
|
version: '0'
|
104
122
|
segments:
|
105
123
|
- 0
|
106
|
-
hash:
|
124
|
+
hash: -1008631629134333472
|
107
125
|
requirements: []
|
108
126
|
rubyforge_project:
|
109
127
|
rubygems_version: 1.8.25
|
@@ -114,3 +132,4 @@ test_files:
|
|
114
132
|
- spec/feature_release_spec.rb
|
115
133
|
- spec/feature_spec.rb
|
116
134
|
- spec/spec_helper.rb
|
135
|
+
- spec/storage_spec.rb
|