feature 0.6.0 → 0.7.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.
@@ -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: