feature 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,7 @@
1
+ ## 0.7.0 (2013-12-07)
2
+
3
+ * add ActiveRecordRepository and a Rails::Generator (bigzed)
4
+
1
5
  ## 0.6.0 (2013-03-24)
2
6
 
3
7
  * add capability for easier testing of activated or deactivated features
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  gem "rake"
4
4
  gem "rspec"
5
+ gem "rspec-mocks"
5
6
 
6
7
  group :test do
7
8
  gem 'coveralls', :require => false
data/README.md CHANGED
@@ -73,7 +73,7 @@ With this approach Feature is higly configurable and not bound to a specific kin
73
73
  ### Rails using YamlRepository
74
74
 
75
75
  # File: Gemfile
76
- gem 'feature' # Or with version specifier, e.g. '~> 0.6.0'
76
+ gem 'feature' # Or with version specifier, e.g. '~> 0.7.0'
77
77
 
78
78
  # File: config/feature.yml
79
79
  features:
@@ -88,3 +88,27 @@ With this approach Feature is higly configurable and not bound to a specific kin
88
88
  <% if Feature.active?(:an_active_feature) %>
89
89
  <%# Feature implementation goes here %>
90
90
  <% end %>
91
+
92
+
93
+ ### Rails using ActiveRecordRepository
94
+
95
+ # File: Gemfile
96
+ gem 'feature' # Or with version specifier, e.g. '~> 0.7.0'
97
+
98
+ # Run generator and migrations
99
+ $ rails g feature:install
100
+ $ rake db:migrate
101
+
102
+ # Add Features to table FeaturesToggle for example in
103
+ # File: db/schema.rb
104
+ FeatureToggle.new(name: "ActiveFeature", active: true)
105
+ FeatureToggle.new(name: "InActiveFeature", active: false)
106
+
107
+ # or in initializer
108
+ # File: config/initializers/feature.rb
109
+ repo.add_active_feature(:active_feature)
110
+
111
+ # File: app/views/example/index.html.erb
112
+ <% if Feature.active?(:an_active_feature) %>
113
+ <%# Feature implementation goes here %>
114
+ <% end %>
@@ -22,6 +22,8 @@
22
22
  #
23
23
  module Feature
24
24
  require 'feature/repository'
25
+ # Only load the generator if Rails is defined
26
+ require 'feature/generators/install_generator' if defined?(Rails)
25
27
 
26
28
  @repository = nil
27
29
  @active_features = nil
@@ -0,0 +1,19 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record'
4
+
5
+ module Feature
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ extend ActiveRecord::Generators::Migration
9
+
10
+ desc 'This generator creates a migration and a model for FeatureToggles.'
11
+ source_root File.expand_path('../templates', __FILE__)
12
+
13
+ def create_model_file
14
+ template 'feature.rb', 'config/initializers/feature.rb'
15
+ template 'feature_toggle.rb', 'app/models/feature_toggle.rb'
16
+ migration_template 'create_feature_toggles.rb', 'db/migrate/create_feature_toggles.rb'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ class CreateFeatureToggles < ActiveRecord::Migration
2
+ def change
3
+ create_table :feature_toggles do |t|
4
+ t.string :name
5
+ t.boolean :active
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ # Set repository to ActiveRecord
2
+ if FeatureToggle.table_exists?
3
+ repo = Feature::Repository::ActiveRecordRepository.new(FeatureToggle)
4
+ Feature.set_repository(repo)
5
+ end
@@ -0,0 +1,6 @@
1
+ class FeatureToggle < ActiveRecord::Base
2
+ attr_accessible :name, :active
3
+
4
+ # Feature name should be present and unique
5
+ validates :name, :presence => true, :uniqueness => true
6
+ end
@@ -3,5 +3,6 @@ module Feature
3
3
  module Repository
4
4
  require 'feature/repository/simple_repository'
5
5
  require 'feature/repository/yaml_repository'
6
+ require 'feature/repository/active_record_repository'
6
7
  end
7
8
  end
@@ -0,0 +1,61 @@
1
+ module Feature
2
+ module Repository
3
+ # AcitveRecordRepository for active feature list
4
+ # Right now we assume you have at least name:string and active:boolean
5
+ # defined in your table.
6
+ #
7
+ # Example usage:
8
+ # repository = ActiveRecordRepository.new(FeatureToggle)
9
+ # repository.add_active_feature(:feature_name)
10
+ # # use repository with Feature
11
+ #
12
+ class ActiveRecordRepository
13
+ # Constructor
14
+ #
15
+ def initialize(model)
16
+ @model = model
17
+ end
18
+
19
+ # Returns list of active features
20
+ #
21
+ # @return [Array<Symbol>] list of active features
22
+ #
23
+ def active_features
24
+ @model.where(:active => true).map { |f| f.name.to_sym }
25
+ end
26
+
27
+ # Add an active feature to repository
28
+ #
29
+ # @param [Symbol] feature the feature to be added
30
+ #
31
+ def add_active_feature(feature)
32
+ check_feature_is_not_symbol(feature)
33
+ check_feature_already_in_list(feature)
34
+ @model.new(:name => feature.to_s, :active => true).save
35
+ end
36
+
37
+ # Checks if the given feature is a not symbol and raises an exception if so
38
+ #
39
+ # @param [Sybmol] feature the feature to be checked
40
+ #
41
+ def check_feature_is_not_symbol(feature)
42
+ if !feature.is_a?(Symbol)
43
+ raise ArgumentError, "given feature #{feature} is not a symbol"
44
+ end
45
+ end
46
+ private :check_feature_is_not_symbol
47
+
48
+ # Checks if given feature is already added to list of active features
49
+ # and raises an exception if so
50
+ #
51
+ # @param [Symbol] feature the feature to be checked
52
+ #
53
+ def check_feature_already_in_list(feature)
54
+ if @model.exists?(feature.to_s)
55
+ raise ArgumentError, "feature :#{feature} already added to list of active features"
56
+ end
57
+ end
58
+ private :check_feature_already_in_list
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ include Feature::Repository
4
+
5
+ describe Feature::Repository::ActiveRecordRepository do
6
+ before(:each) do
7
+ # Mock the model
8
+ @features = double("FeatureToggle")
9
+ @repository = ActiveRecordRepository.new(@features)
10
+ end
11
+
12
+ it "should have no active features after initialization" do
13
+ @features.stub(:where) { Hash.new }
14
+
15
+ @repository.active_features.should == []
16
+ end
17
+
18
+ it "should add an active feature" do
19
+ @features.should_receive(:exists?).with("feature_a").and_return(false)
20
+ @features.should_receive(:new).with(:name => "feature_a",:active => true).and_return(stub(:save => true))
21
+
22
+ @repository.add_active_feature :feature_a
23
+ end
24
+
25
+ it "should raise an exception when adding not a symbol as active feature" do
26
+ expect {
27
+ @repository.add_active_feature 'feature_a'
28
+ }.to raise_error(ArgumentError, "given feature feature_a is not a symbol")
29
+ end
30
+
31
+ it "should raise an exception when adding a active feature already added as active" do
32
+ @features.should_receive(:new).with(:name => "feature_a",:active => true).and_return(stub(:save => true))
33
+ @features.stub(:exists?).and_return(false,true)
34
+
35
+ @repository.add_active_feature :feature_a
36
+ expect {
37
+ @repository.add_active_feature :feature_a
38
+ }.to raise_error(ArgumentError, "feature :feature_a already added to list of active features")
39
+ end
40
+ end
@@ -87,7 +87,7 @@ EOF
87
87
  repo = YamlRepository.new("/this/file/should/not/exist")
88
88
  lambda do
89
89
  repo.active_features
90
- end.should raise_error(Errno::ENOENT, /No such file or directory -/)
90
+ end.should raise_error(Errno::ENOENT, /No such file or directory/)
91
91
  end
92
92
 
93
93
  it "should raise exception on invalid yaml" do
metadata CHANGED
@@ -1,37 +1,33 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: feature
3
- version: !ruby/object:Gem::Version
4
- hash: 7
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 6
9
- - 0
10
- version: 0.6.0
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Markus Gerdes
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2013-03-24 00:00:00 Z
12
+ date: 2013-12-07 00:00:00.000000000 Z
19
13
  dependencies: []
20
-
21
14
  description:
22
15
  email: github@mgsnova.de
23
16
  executables: []
24
-
25
17
  extensions: []
26
-
27
18
  extra_rdoc_files: []
28
-
29
- files:
19
+ files:
30
20
  - lib/feature.rb
21
+ - lib/feature/generators/install_generator.rb
22
+ - lib/feature/generators/templates/create_feature_toggles.rb
23
+ - lib/feature/generators/templates/feature.rb
24
+ - lib/feature/generators/templates/feature_toggle.rb
31
25
  - lib/feature/repository.rb
26
+ - lib/feature/repository/active_record_repository.rb
32
27
  - lib/feature/repository/simple_repository.rb
33
28
  - lib/feature/repository/yaml_repository.rb
34
29
  - lib/feature/testing.rb
30
+ - spec/feature/active_record_repository_spec.rb
35
31
  - spec/feature/feature_spec.rb
36
32
  - spec/feature/simple_repository_spec.rb
37
33
  - spec/feature/testing_spec.rb
@@ -43,37 +39,26 @@ files:
43
39
  - CHANGELOG.md
44
40
  homepage: http://github.com/mgsnova/feature
45
41
  licenses: []
46
-
47
42
  post_install_message:
48
43
  rdoc_options: []
49
-
50
- require_paths:
44
+ require_paths:
51
45
  - lib
52
- required_ruby_version: !ruby/object:Gem::Requirement
46
+ required_ruby_version: !ruby/object:Gem::Requirement
53
47
  none: false
54
- requirements:
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- hash: 3
58
- segments:
59
- - 0
60
- version: "0"
61
- required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
53
  none: false
63
- requirements:
64
- - - ">="
65
- - !ruby/object:Gem::Version
66
- hash: 3
67
- segments:
68
- - 0
69
- version: "0"
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
70
58
  requirements: []
71
-
72
59
  rubyforge_project:
73
60
  rubygems_version: 1.8.24
74
61
  signing_key:
75
62
  specification_version: 3
76
63
  summary: Feature Toggle library for ruby
77
64
  test_files: []
78
-
79
- has_rdoc: