acts_as_featureable 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,9 @@
1
1
  module ActsAsFeatureable
2
- class Engine < ::Rails::Engine
3
- config.generators do |g|
4
- g.test_framework :rspec, :fixture => false
5
- g.assets false
6
- g.helper false
7
- end
8
- end
2
+ class Engine < ::Rails::Engine
3
+ config.generators do |g|
4
+ g.test_framework :rspec, :fixture => false
5
+ g.assets false
6
+ g.helper false
7
+ end
8
+ end
9
9
  end
@@ -0,0 +1,96 @@
1
+ module ActsAsFeatureable
2
+ module FeatureAdditions
3
+ def self.included(feature_model)
4
+ feature_model.belongs_to :featureable, polymorphic: true
5
+
6
+ feature_model.scope :ordered, ->{ feature_model.order('position ASC') }
7
+
8
+ feature_model.before_validation :assign_title, :assign_summary, :assign_position
9
+
10
+ feature_model.validate :feature_limit_not_reached, :ensure_categories
11
+
12
+ feature_model.validates_presence_of :featureable_id, :featureable_type
13
+
14
+ feature_model.validates_numericality_of :position
15
+
16
+ private
17
+
18
+ def ensure_categories
19
+ cats = ::ActsAsFeatureable::categories
20
+ # Allow all categories if set to false
21
+ if cats && self.category && !cats.include?(self.category.to_sym)
22
+ errors.add(:category, " is not in the list [#{cats.join(',')}]")
23
+ end
24
+ end
25
+
26
+ def feature_limit_not_reached
27
+ limit = ActsAsFeatureable.feature_limit
28
+ errors.add(:base, %q{
29
+ The feature limit of #{limit} has been reached. \
30
+ Please delete or change an existing feature.
31
+ }) if ActsAsFeatureable.categories ? Feature.where(category: self.category).count >= limit : Feature.count >= limit
32
+ end
33
+
34
+ def assign_title
35
+ # If there is no title given, check the model.
36
+ # Will check for the attributes in ActsAsFeatureable.auto_title_assign_list.
37
+ unless self.title
38
+ ActsAsFeatureable.auto_title_assign_list.each do |attr|
39
+ if featureable.respond_to?(attr)
40
+ self.title = featureable.send(attr)
41
+ break
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def assign_summary
48
+ # If there is no summary given, check the model.
49
+ # Will check for the attributes in ActsAsFeatureable.auto_summary_assign_list.
50
+ unless self.summary
51
+ ActsAsFeatureable.auto_summary_assign_list.each do |attr|
52
+ if featureable.respond_to?(attr)
53
+ self.summary = featureable.send(attr)
54
+ break
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def assign_position
61
+ # If there is no position given, or the position given is already taken,
62
+ # assign the lowest open position. Otherwise assign it.
63
+ all_positions = if ActsAsFeatureable.categories
64
+ Feature.select('features.position, features.category').where(category: self.category).map(&:position).sort
65
+ else
66
+ Feature.select('features.position').map(&:position).sort
67
+ end
68
+
69
+ if !self.position || (self.position && all_positions.include?(self.position))
70
+ # Find lowest, non-taken position
71
+ (1..ActsAsFeatureable.feature_limit).each do |n|
72
+ next if all_positions.include? n
73
+ self.position = n
74
+ break
75
+ end
76
+ end
77
+ end
78
+
79
+ def feature_model.method_missing(mehtod_name, *args, &block)
80
+ if ActsAsFeatureable.categories &&
81
+ ActsAsFeatureable.categories.include?(mehtod_name)
82
+ self.scope mehtod_name, -> { self.where(category: mehtod_name) }
83
+ self.send(mehtod_name)
84
+ else
85
+ super
86
+ end
87
+ end
88
+
89
+ def respond_to_missing?(method_name, include_private = false)
90
+ (ActsAsFeatureable.categories &&
91
+ ActsAsFeatureable.categories.include?(method_name)) ||
92
+ super
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ module Acts
3
+ module FeatureableAdditions
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def acts_as_featureable
10
+ has_many :features, :as => :featureable, :dependent => :destroy
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ ActiveRecord::Base.send(:include, ActiveRecord::Acts::FeatureableAdditions)
@@ -1,3 +1,3 @@
1
1
  module ActsAsFeatureable
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,16 +1,16 @@
1
1
  require 'rails/generators/migration'
2
2
 
3
3
  class FeaturesGenerator < Rails::Generators::Base
4
- include Rails::Generators::Migration
5
-
6
- source_root File.expand_path("../templates", __FILE__)
7
-
8
- def self.next_migration_number(path)
9
- Time.now.utc.strftime("%Y%m%d%H%M%S")
10
- end
11
-
12
- def create_featureable_file
13
- copy_file "initializer.rb", "config/initializers/acts_as_featureable.rb"
14
- migration_template "create_features.rb", "db/migrate/create_features.rb"
15
- end
4
+ include Rails::Generators::Migration
5
+
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def self.next_migration_number(path)
9
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
10
+ end
11
+
12
+ def create_featureable_file
13
+ copy_file "initializer.rb", "config/initializers/acts_as_featureable.rb"
14
+ migration_template "create_features.rb", "db/migrate/create_features.rb"
15
+ end
16
16
  end
@@ -1,14 +1,14 @@
1
1
  class CreateFeatures < ActiveRecord::Migration
2
- def change
3
- create_table :features do |t|
4
- t.references :featureable, :polymorphic => true
5
- t.string :title
6
- t.text :summary
7
- t.integer :position, :null => false
8
- t.string :category
9
- t.timestamps
10
- end
11
-
12
- add_index :features, [:featureable_type, :featureable_id]
13
- end
2
+ def change
3
+ create_table :features do |t|
4
+ t.references :featureable, :polymorphic => true
5
+ t.string :title
6
+ t.text :summary
7
+ t.integer :position, :null => false
8
+ t.string :category
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :features, [:featureable_type, :featureable_id]
13
+ end
14
14
  end
@@ -1,15 +1,15 @@
1
1
  ActsAsFeatureable.setup do |config|
2
- # Set the maximum limit of features availible for your app.
3
- config.feature_limit = 10
4
-
5
- # Set the order of auto title assigning.
6
- config.auto_title_assign_list = [:title, :name]
7
-
8
- # Set the order of auto summary assigning.
9
- config.auto_summary_assign_list = [:summary, :caption, :tldr, :content, :text]
10
-
11
- # Limit the categories you wish to use.
12
- # => [:main, :articles, :images]
13
- # false allows unlimited categories.
14
- config.categories = false
2
+ # Set the maximum limit of features availible for your app.
3
+ config.feature_limit = 10
4
+
5
+ # Set the order of auto title assigning.
6
+ config.auto_title_assign_list = [:title, :name]
7
+
8
+ # Set the order of auto summary assigning.
9
+ config.auto_summary_assign_list = [:summary, :caption, :tldr, :content, :text]
10
+
11
+ # Limit the categories you wish to use.
12
+ # => [:main, :articles, :images]
13
+ # false allows unlimited categories.
14
+ config.categories = false
15
15
  end
@@ -1,3 +1,3 @@
1
1
  class Topic < ActiveRecord::Base
2
- acts_as_featureable
2
+ acts_as_featureable
3
3
  end
@@ -1,17 +1,17 @@
1
1
  ActiveRecord::Schema.define :version => 0 do
2
- create_table :features do |t|
3
- t.references :featureable, :polymorphic => true
4
- t.string :title
5
- t.text :summary
6
- t.integer :position, :null => false
7
- t.string :category
8
- t.timestamps
9
- end
10
-
11
- add_index :features, [:featureable_type, :featureable_id]
12
-
13
- create_table :topics do |t|
14
- t.string :title
15
- t.text :summary
16
- end
2
+ create_table :features do |t|
3
+ t.references :featureable, :polymorphic => true
4
+ t.string :title
5
+ t.text :summary
6
+ t.integer :position, :null => false
7
+ t.string :category
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :features, [:featureable_type, :featureable_id]
12
+
13
+ create_table :topics do |t|
14
+ t.string :title
15
+ t.text :summary
16
+ end
17
17
  end
@@ -1,6 +1,6 @@
1
1
  FactoryGirl.define do
2
- factory :topic do
3
- title "Title"
4
- summary "Summary"
5
- end
2
+ factory :topic do
3
+ title "Title"
4
+ summary "Summary"
5
+ end
6
6
  end
@@ -1,24 +1,24 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe FeaturesHelper do
4
- before :each do
5
- @topic = Topic.create!
6
- end
7
-
8
- describe "features_form_for" do
9
- it "should render the form for a new feature" do
10
- helper.feature_form_for(@topic).should =~ /id="new_feature"/
11
- end
12
- end
13
-
14
- describe "features_for" do
15
- it "should be empty if there are no features for the featureable" do
16
- helper.features_for(@topic).should be_blank
17
- end
18
-
19
- it "should render a list of features" do
20
- @topic.features.create!
21
- helper.features_for(@topic).should =~ /class="feature"/
22
- end
23
- end
4
+ before :each do
5
+ @topic = Topic.create!
6
+ end
7
+
8
+ describe "features_form_for" do
9
+ it "should render the form for a new feature" do
10
+ helper.feature_form_for(@topic).should =~ /id="new_feature"/
11
+ end
12
+ end
13
+
14
+ describe "features_for" do
15
+ it "should be empty if there are no features for the featureable" do
16
+ helper.features_for(@topic).should be_blank
17
+ end
18
+
19
+ it "should render a list of features" do
20
+ @topic.features.create!
21
+ helper.features_for(@topic).should =~ /class="feature"/
22
+ end
23
+ end
24
24
  end
@@ -1,131 +1,126 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Feature do
4
- before :each do
5
- Feature.delete_all
6
- @topic = Topic.create!
7
- end
8
-
9
- subject { @topic.features.create! }
10
-
11
- it { should be_valid }
12
- it { should belong_to :featureable }
13
- it { should validate_numericality_of :position }
14
- it { should validate_presence_of :featureable_id }
15
- it { should validate_presence_of :featureable_type }
16
-
17
- ## ENSURE CATEGORIES ##
18
- it "should allow any categories by default" do
19
- @topic.features.create!(category: 'anything').errors.count.should eql 0
20
- end
21
-
22
- describe "with category limits" do
23
- before :each do
24
- ActsAsFeatureable.categories = [:default]
25
- end
26
-
27
- it "should allow a category that is in the list" do
28
- @topic.features.create(category: :default).errors.count.should eq 0
29
- end
30
-
31
- it "should not allow a category that is not in the list" do
32
- feature = @topic.features.create(category: :foo)
33
-
34
- feature.errors.count.should eq 1
35
- feature.errors.messages.keys.should include(:category)
36
- end
37
-
38
- ## CREATE SCOPES ##
39
- it "should create scopes for the default categories" do
40
- Feature.default
41
- end
42
-
43
- it "should return all the features of the scope for the deafult categories" do
44
- @topic.features.create!(category: :default)
45
-
46
- Feature.default.size.should eq 1
47
- end
48
- end
49
-
50
- ## LIMIT VALIDATION ##
51
- it "should only allow the default number of features to be made" do
52
- limit = ActsAsFeatureable.feature_limit
53
-
54
- # Create the limit of features
55
- limit.times do
56
- @topic.features.create!
57
- end
58
-
59
- # Attempt to create an additional feature
60
- expect { @topic.features.create! }.to raise_error ActiveRecord::RecordInvalid
61
- end
62
-
63
- describe "with category limits" do
64
- before :each do
65
- ActsAsFeatureable.categories = [:one, :two]
66
-
67
- limit = ActsAsFeatureable.feature_limit
68
-
69
- # Create the limit of features
70
- limit.times do
71
- @topic.features.create!(category: :one)
72
- end
73
- end
74
-
75
- it "should only allow the default number of features per category to be made" do
76
- # Attempt to create an additional feature
77
- expect { @topic.features.create!(category: :one) }.to raise_error ActiveRecord::RecordInvalid
78
- end
79
-
80
- it "should allow more features to be made of other categories when one is full" do
81
- expect { @topic.features.create!(category: :two) }.to_not raise_error ActiveRecord::RecordInvalid
82
- end
83
- end
84
-
85
- ## TITLE ##
86
- describe "with featureable" do
87
- before :each do
88
- @topic = Topic.create!(:title => 'Title')
89
- end
90
-
91
- it "should assign associated model's title" do
92
- feature = @topic.features.create!(:featureable => @topic)
93
-
94
- feature.title.should eql @topic.title
95
- end
96
-
97
- it "should overwrite associated model's title" do
98
- feature = @topic.features.create!(:featureable => @topic, :title => 'New Title')
99
-
100
- feature.title.should eql 'New Title'
101
- end
102
-
103
- ## SUMMARY ##
104
- it "should assign associated model's summary" do
105
- feature = @topic.features.create!(:featureable => @topic)
106
-
107
- feature.summary.should eql @topic.summary
108
- end
109
-
110
- it "should overwrite associated model's summary" do
111
- feature = @topic.features.create!(:featureable => @topic, :summary => 'New Summary')
112
-
113
- feature.summary.should eql 'New Summary'
114
- end
115
- end
116
-
117
- ## POSITION ##
118
- it "should assign a default position" do
119
- subject.position.should_not be_nil
120
- end
121
-
122
- it "should assign a default position of 1 if there are none existing" do
123
- subject.position.should eql 1
124
- end
125
-
126
- it "should assign the next position in line if it already exists" do
127
- subject
128
- @topic.features.create!(:position => 1).position.should eql 2
129
- end
4
+ before :each do
5
+ Feature.delete_all
6
+ @topic = Topic.create!
7
+ end
8
+
9
+ subject { @topic.features.create! }
10
+
11
+ it { should be_valid }
12
+ it { should belong_to :featureable }
13
+ it { should validate_numericality_of :position }
14
+ it { should validate_presence_of :featureable_id }
15
+ it { should validate_presence_of :featureable_type }
16
+
17
+ ## ENSURE CATEGORIES ##
18
+ it "should allow any categories by default" do
19
+ @topic.features.create!(category: 'anything').errors.count.should eql 0
20
+ end
21
+
22
+ describe "with category limits" do
23
+ before :each do
24
+ ActsAsFeatureable.categories = [:default]
25
+ end
26
+
27
+ it "should allow a category that is in the list" do
28
+ @topic.features.create(category: :default).errors.count.should eq 0
29
+ end
30
+
31
+ it "should not allow a category that is not in the list" do
32
+ feature = @topic.features.create(category: :foo)
33
+
34
+ feature.errors.count.should eq 1
35
+ feature.errors.messages.keys.should include(:category)
36
+ end
37
+
38
+ ## CREATE SCOPES ##
39
+ it "should create scopes for the default categories" do
40
+ Feature.default
41
+ end
42
+
43
+ it "should return all the features of the scope for the deafult categories" do
44
+ @topic.features.create!(category: :default)
45
+
46
+ Feature.default.size.should eq 1
47
+ end
48
+ end
49
+
50
+ ## LIMIT VALIDATION ##
51
+ it "should only allow the default number of features to be made" do
52
+ # Create the limit of features
53
+ ActsAsFeatureable.feature_limit.times do
54
+ @topic.features.create!
55
+ end
56
+
57
+ # Attempt to create an additional feature
58
+ expect { @topic.features.create! }.to raise_error ActiveRecord::RecordInvalid
59
+ end
60
+
61
+ describe "with category limits" do
62
+ before :each do
63
+ ActsAsFeatureable.categories = [:one, :two]
64
+
65
+ # Create the limit of features
66
+ ActsAsFeatureable.feature_limit.times do
67
+ @topic.features.create!(category: :one)
68
+ end
69
+ end
70
+
71
+ it "should only allow the default number of features per category to be made" do
72
+ # Attempt to create an additional feature
73
+ expect { @topic.features.create!(category: :one) }.to raise_error ActiveRecord::RecordInvalid
74
+ end
75
+
76
+ it "should allow more features to be made of other categories when one is full" do
77
+ expect { @topic.features.create!(category: :two) }.to_not raise_error ActiveRecord::RecordInvalid
78
+ end
79
+ end
80
+
81
+ ## TITLE ##
82
+ describe "with featureable" do
83
+ before :each do
84
+ @topic = Topic.create!(:title => 'Title')
85
+ end
86
+
87
+ it "should assign associated model's title" do
88
+ feature = @topic.features.create!(:featureable => @topic)
89
+
90
+ feature.title.should eql @topic.title
91
+ end
92
+
93
+ it "should overwrite associated model's title" do
94
+ feature = @topic.features.create!(:featureable => @topic, :title => 'New Title')
95
+
96
+ feature.title.should eql 'New Title'
97
+ end
98
+
99
+ ## SUMMARY ##
100
+ it "should assign associated model's summary" do
101
+ feature = @topic.features.create!(:featureable => @topic)
102
+
103
+ feature.summary.should eql @topic.summary
104
+ end
105
+
106
+ it "should overwrite associated model's summary" do
107
+ feature = @topic.features.create!(:featureable => @topic, :summary => 'New Summary')
108
+
109
+ feature.summary.should eql 'New Summary'
110
+ end
111
+ end
112
+
113
+ ## POSITION ##
114
+ it "should assign a default position" do
115
+ subject.position.should_not be_nil
116
+ end
117
+
118
+ it "should assign a default position of 1 if there are none existing" do
119
+ subject.position.should eql 1
120
+ end
121
+
122
+ it "should assign the next position in line if it already exists" do
123
+ subject
124
+ @topic.features.create!(:position => 1).position.should eql 2
125
+ end
130
126
  end
131
-