partisan 0.1.1 → 0.2

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.
data/README.md CHANGED
@@ -11,7 +11,7 @@ It’s heavily inspired by `acts_as_follower`. However, it’s not 100% compatib
11
11
  But I also added awesome new ones:
12
12
 
13
13
  * You can use `following_team_ids` but also `following_team_names` (basically any `following_team_<column>s`). It takes advantage of the `pluck` method, so it doesn’t create an instance of each follower, it just return the relevant column values. (Go check `pluck` documentation, it’s simply awesome).
14
- * The `followers` and `followings` mthods now return an `ActiveRecord::Relation` for easy chaining, scoping, counting, pagination, etc.
14
+ * The `followers` and `followings` methods now return an `ActiveRecord::Relation` for easy chaining, scoping, counting, pagination, etc.
15
15
 
16
16
  ## Installation
17
17
 
@@ -65,6 +65,8 @@ fan.following?(band)
65
65
  # => false
66
66
  ```
67
67
 
68
+ ### Cache counters
69
+
68
70
  Most of the times, you would want to get a quick look at about how many fans follow a certain resource. That could be an expensive operation.
69
71
 
70
72
  However, if the *followed* record has a `followers_count` column, Partisan will populate its value with how many followers the record has.
@@ -81,6 +83,52 @@ band.followers_count
81
83
 
82
84
  The same concept applies to `followable` with a `following_count` column.
83
85
 
86
+ ### Callbacks
87
+
88
+ You can define callbacks that will be triggered before or after a following relationship is created.
89
+
90
+ If a `before_follow` callback returns `false`, it will halt the call and the relationship will be not be saved (much like `ActiveRecords`’s `before_save` callbacks).
91
+
92
+ ```ruby
93
+ class Fan < ActiveRecord::Base
94
+ acts_as_follower
95
+ after_follow :send_notification
96
+
97
+ def send_notification
98
+ puts "#{self} is now following #{self.just_followed}"
99
+ end
100
+ end
101
+
102
+ class Band < ActiveRecord::Base
103
+ acts_as_followable
104
+ before_follow :ensure_active_fan
105
+
106
+ def ensure_active_fan
107
+ self.about_to_be_followed_by.active?
108
+ end
109
+ end
110
+ ```
111
+
112
+ The available callbacks are:
113
+
114
+ #### Follower
115
+
116
+ | Callback | Reference to the followable |
117
+ | ------------------|-----------------------------|
118
+ | `before_follow` | `self.about_to_follow` |
119
+ | `after_follow` | `self.just_followed` |
120
+ | `before_unfollow` | `self.about_to_unfollow` |
121
+ | `after_unfollow` | `self.just_unfollowed` |
122
+
123
+ #### Followable
124
+
125
+ | Callback | Reference to the follower |
126
+ | ------------------|----------------------------------|
127
+ | `before_follow` | `self.about_to_be_followed_by` |
128
+ | `after_follow` | `self.just_followed_by` |
129
+ | `before_unfollow` | `self.about_to_by_unfollowed_by` |
130
+ | `after_unfollow` | `self.just_unfollowed_by` |
131
+
84
132
  ## License
85
133
 
86
134
  `Partisan` is © 2013 [Mirego](http://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/partisan/blob/master/LICENSE.md) file.
@@ -7,8 +7,8 @@ class AddFollowsMigration < ActiveRecord::Migration
7
7
  t.timestamps
8
8
  end
9
9
 
10
- add_index :follows, ["follower_id", "follower_type"], name: "fk_follows"
11
- add_index :follows, ["followable_id", "followable_type"], name: "fk_followables"
10
+ add_index :follows, ['follower_id', 'follower_type'], name: 'index_partisan_followers'
11
+ add_index :follows, ['followable_id', 'followable_type'], name: 'index_partisan_followables'
12
12
  end
13
13
 
14
14
  def down
@@ -8,8 +8,19 @@ require "partisan/follower"
8
8
  require "partisan/followable"
9
9
 
10
10
  module Partisan
11
-
12
11
  include Partisan::FollowHelper
12
+
13
+ def self.inject_into_active_record
14
+ @inject_into_active_record ||= Proc.new do
15
+ def self.acts_as_follower
16
+ self.send :include, Partisan::Follower
17
+ end
18
+
19
+ def self.acts_as_followable
20
+ self.send :include, Partisan::Followable
21
+ end
22
+ end
23
+ end
13
24
  end
14
25
 
15
26
  require 'partisan/railtie' if defined?(Rails) && Rails::VERSION::MAJOR >= 3
@@ -14,6 +14,34 @@ module Partisan
14
14
  after_create :update_follow_counter
15
15
  after_destroy :update_follow_counter
16
16
 
17
+ # Follower's :follow callbacks
18
+ around_create do |follow, blk|
19
+ self.follower.about_to_follow = self.follower.just_followed = self.followable
20
+ self.follower.run_callbacks :follow, &blk
21
+ self.follower.about_to_follow = self.follower.just_followed = nil
22
+ end
23
+
24
+ # Followable's :follow callbacks
25
+ around_create do |follow, blk|
26
+ self.followable.about_to_be_followed_by = self.followable.just_followed_by = self.follower
27
+ self.followable.run_callbacks :follow, &blk
28
+ self.followable.about_to_be_followed_by = self.followable.just_followed_by = nil
29
+ end
30
+
31
+ # Follower's :unfollow callbacks
32
+ around_destroy do |follow, blk|
33
+ self.follower.about_to_unfollow = self.follower.just_unfollowed = self.followable
34
+ self.follower.run_callbacks :unfollow, &blk
35
+ self.follower.about_to_unfollow = self.follower.just_unfollowed = nil
36
+ end
37
+
38
+ # Followable's :unfollow callbacks
39
+ around_destroy do |follow, blk|
40
+ self.followable.about_to_be_unfollowed_by = self.followable.just_unfollowed_by = self.follower
41
+ self.followable.run_callbacks :unfollow, &blk
42
+ self.followable.about_to_be_unfollowed_by = self.followable.just_unfollowed_by = nil
43
+ end
44
+
17
45
  protected
18
46
 
19
47
  def update_follow_counter
@@ -1,10 +1,15 @@
1
1
  module Partisan
2
2
  module Followable
3
3
  extend ActiveSupport::Concern
4
+ extend ActiveModel::Callbacks
5
+
4
6
  include Partisan::FollowHelper
5
7
 
6
8
  included do
7
9
  has_many :followings, as: :followable, class_name: 'Partisan::Follow', dependent: :destroy
10
+ define_model_callbacks :follow
11
+ define_model_callbacks :unfollow
12
+ attr_accessor :about_to_be_followed_by, :just_followed_by, :about_to_be_unfollowed_by, :just_unfollowed_by
8
13
  end
9
14
 
10
15
  # Return true or false if the resource is following another
@@ -1,10 +1,14 @@
1
1
  module Partisan
2
2
  module Follower
3
3
  extend ActiveSupport::Concern
4
+ extend ActiveModel::Callbacks
4
5
  include Partisan::FollowHelper
5
6
 
6
7
  included do
7
8
  has_many :follows, as: :follower, class_name: 'Partisan::Follow', dependent: :destroy
9
+ define_model_callbacks :follow
10
+ define_model_callbacks :unfollow
11
+ attr_accessor :about_to_follow, :just_followed, :about_to_unfollow, :just_unfollowed
8
12
  end
9
13
 
10
14
  # Add follow record if it doesn’t exist
@@ -47,7 +51,7 @@ module Partisan
47
51
  def following?(resource)
48
52
  return false if self == resource
49
53
 
50
- fetch_follows(resource).exists?
54
+ !!fetch_follows(resource).exists?
51
55
  end
52
56
 
53
57
  # Get all follows record related to a resource
@@ -4,15 +4,7 @@ require 'rails'
4
4
  module Partisan
5
5
  class Railtie < Rails::Railtie
6
6
  initializer "follows.active_record" do |app|
7
- ActiveSupport.on_load :active_record do
8
- def self.acts_as_follower
9
- self.send :include, Partisan::Follower
10
- end
11
-
12
- def self.acts_as_followable
13
- self.send :include, Partisan::Followable
14
- end
15
- end
7
+ ActiveSupport.on_load :active_record, {}, &Partisan.inject_into_active_record
16
8
  end
17
9
  end
18
10
  end
@@ -1,3 +1,3 @@
1
1
  module Partisan
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2"
3
3
  end
@@ -80,6 +80,112 @@ describe Partisan::Follower do
80
80
  end
81
81
  end
82
82
 
83
+ describe :Callbacks do
84
+ before do
85
+ class Buffer
86
+ def self.tmp_value=(tmp_value)
87
+ @tmp_value = tmp_value
88
+ end
89
+
90
+ def self.tmp_value
91
+ @tmp_value
92
+ end
93
+ end
94
+ end
95
+
96
+ describe 'Follower callbacks' do
97
+ describe :before_follow do
98
+ before do
99
+ follower 'User' do
100
+ before_follow { Buffer.tmp_value = self.about_to_follow }
101
+ end
102
+ end
103
+
104
+ it { expect{ user.follow(band) }.to change{ Buffer.tmp_value }.to(band) }
105
+ end
106
+
107
+ describe :after_follow do
108
+ before do
109
+ follower 'User' do
110
+ after_follow { Buffer.tmp_value = self.just_followed }
111
+ end
112
+ end
113
+
114
+ it { expect{ user.follow(band) }.to change{ Buffer.tmp_value }.to(band) }
115
+ end
116
+
117
+ describe :before_unfollow do
118
+ before do
119
+ follower 'User' do
120
+ before_unfollow { Buffer.tmp_value = self.about_to_unfollow }
121
+ end
122
+
123
+ user.follow(band)
124
+ end
125
+
126
+ it { expect{ user.unfollow(band) }.to change{ Buffer.tmp_value }.to(band) }
127
+ end
128
+
129
+ describe :after_unfollow do
130
+ before do
131
+ follower 'User' do
132
+ after_unfollow { Buffer.tmp_value = self.about_to_unfollow }
133
+ end
134
+
135
+ user.follow(band)
136
+ end
137
+
138
+ it { expect{ user.unfollow(band) }.to change{ Buffer.tmp_value }.to(band) }
139
+ end
140
+ end
141
+
142
+ describe 'Followable callbacks' do
143
+ describe :before_follow do
144
+ before do
145
+ followable 'Band' do
146
+ before_follow { Buffer.tmp_value = self.about_to_be_followed_by }
147
+ end
148
+ end
149
+
150
+ it { expect{ user.follow(band) }.to change{ Buffer.tmp_value }.to(user) }
151
+ end
152
+
153
+ describe :after_follow do
154
+ before do
155
+ followable 'Band' do
156
+ after_follow { Buffer.tmp_value = self.just_followed_by }
157
+ end
158
+ end
159
+
160
+ it { expect{ user.follow(band) }.to change{ Buffer.tmp_value }.to(user) }
161
+ end
162
+
163
+ describe :before_unfollow do
164
+ before do
165
+ followable 'Band' do
166
+ before_unfollow { Buffer.tmp_value = self.about_to_be_unfollowed_by }
167
+ end
168
+
169
+ user.follow(band)
170
+ end
171
+
172
+ it { expect{ user.unfollow(band) }.to change{ Buffer.tmp_value }.to(user) }
173
+ end
174
+
175
+ describe :after_unfollow do
176
+ before do
177
+ followable 'Band' do
178
+ after_unfollow { Buffer.tmp_value = self.just_unfollowed_by }
179
+ end
180
+
181
+ user.follow(band)
182
+ end
183
+
184
+ it { expect{ user.unfollow(band) }.to change{ Buffer.tmp_value }.to(user) }
185
+ end
186
+ end
187
+ end
188
+
83
189
  describe :AliasMethods do
84
190
  subject { User.create }
85
191
 
@@ -7,8 +7,9 @@ require 'partisan'
7
7
 
8
8
  # Require our macros and extensions
9
9
  Dir[File.expand_path('../../spec/support/macros/*.rb', __FILE__)].map(&method(:require))
10
- Dir[File.expand_path('../../spec/support/extensions/*.rb', __FILE__)].map(&method(:require))
11
10
 
11
+ # Inject our methods into ActiveRecord (like our railtie does)
12
+ ActiveRecord::Base.class_eval(&Partisan.inject_into_active_record)
12
13
 
13
14
  RSpec.configure do |config|
14
15
  # Include our macros
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: partisan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: '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: 2013-06-24 00:00:00.000000000 Z
12
+ date: 2013-07-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -120,7 +120,6 @@ files:
120
120
  - spec/followable_spec.rb
121
121
  - spec/follower_spec.rb
122
122
  - spec/spec_helper.rb
123
- - spec/support/extensions/active_record.rb
124
123
  - spec/support/macros/database_macros.rb
125
124
  - spec/support/macros/model_macros.rb
126
125
  homepage: https://github.com/simonprev/partisan
@@ -138,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
137
  version: '0'
139
138
  segments:
140
139
  - 0
141
- hash: -161122835352919844
140
+ hash: -352093583781721099
142
141
  required_rubygems_version: !ruby/object:Gem::Requirement
143
142
  none: false
144
143
  requirements:
@@ -147,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
146
  version: '0'
148
147
  segments:
149
148
  - 0
150
- hash: -161122835352919844
149
+ hash: -352093583781721099
151
150
  requirements: []
152
151
  rubyforge_project:
153
152
  rubygems_version: 1.8.23
@@ -159,6 +158,5 @@ test_files:
159
158
  - spec/followable_spec.rb
160
159
  - spec/follower_spec.rb
161
160
  - spec/spec_helper.rb
162
- - spec/support/extensions/active_record.rb
163
161
  - spec/support/macros/database_macros.rb
164
162
  - spec/support/macros/model_macros.rb
@@ -1,9 +0,0 @@
1
- class ActiveRecord::Base
2
- def self.acts_as_follower
3
- self.send :include, Partisan::Follower
4
- end
5
-
6
- def self.acts_as_followable
7
- self.send :include, Partisan::Followable
8
- end
9
- end