acts_as_featureable 0.0.2 → 0.0.3

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,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
-