socialization 0.2.2 → 0.3.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.
- data/.travis.yml +8 -0
- data/Appraisals +4 -4
- data/README.rdoc +68 -8
- data/demo/demo_app/Gemfile +2 -2
- data/demo/demo_app/app/models/comment.rb +5 -0
- data/demo/demo_app/app/models/mention.rb +3 -0
- data/demo/demo_app/app/models/user.rb +1 -0
- data/demo/demo_app/db/migrate/20120221200644_create_mentions.rb +14 -0
- data/demo/demo_app/db/migrate/20120221202703_create_comments.rb +9 -0
- data/demo/demo_app/db/schema.rb +18 -1
- data/demo/demo_app/db/seeds.rb +3 -0
- data/gemfiles/activerecord30.gemfile +6 -0
- data/gemfiles/activerecord30.gemfile.lock +23 -0
- data/gemfiles/activerecord31.gemfile +6 -0
- data/gemfiles/activerecord31.gemfile.lock +25 -0
- data/gemfiles/activerecord32.gemfile +6 -0
- data/gemfiles/activerecord32.gemfile.lock +25 -0
- data/generators/socialization/USAGE +1 -1
- data/generators/socialization/socialization_generator.rb +8 -4
- data/generators/socialization/templates/migration_mentions.rb +14 -0
- data/generators/socialization/templates/model_mention.rb +3 -0
- data/lib/generators/socialization/socialization_generator.rb +8 -4
- data/lib/socialization/follow_store.rb +8 -8
- data/lib/socialization/followable.rb +26 -15
- data/lib/socialization/follower.rb +32 -21
- data/lib/socialization/hello.rb +21 -5
- data/lib/socialization/like_store.rb +8 -8
- data/lib/socialization/likeable.rb +26 -15
- data/lib/socialization/liker.rb +36 -21
- data/lib/socialization/mention_store.rb +14 -0
- data/lib/socialization/mentionable.rb +36 -0
- data/lib/socialization/mentionner.rb +47 -0
- data/lib/socialization/version.rb +1 -1
- data/test/follow_test.rb +36 -6
- data/test/like_test.rb +36 -6
- data/test/mention_test.rb +107 -0
- data/test/test_helper.rb +61 -0
- data/test/world_test.rb +34 -24
- metadata +33 -16
@@ -1,23 +1,34 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
def is_followable?
|
4
|
+
false
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
1
9
|
module Socialization
|
2
10
|
module Followable
|
3
|
-
|
4
|
-
base.class_eval do
|
5
|
-
# A following is the Follow record of the follower following self.
|
6
|
-
has_many :followings, :as => :followable, :dependent => :destroy, :class_name => 'Follow'
|
11
|
+
extend ActiveSupport::Concern
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
13
|
+
included do
|
14
|
+
# A following is the Follow record of the follower following self.
|
15
|
+
has_many :followings, :as => :followable, :dependent => :destroy, :class_name => 'Follow'
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
def is_followable?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def followed_by?(follower)
|
22
|
+
raise ArgumentError, "#{follower} is not a follower!" unless follower.is_follower?
|
23
|
+
!self.followings.where(:follower_type => follower.class.to_s, :follower_id => follower.id).empty?
|
24
|
+
end
|
16
25
|
|
17
|
-
|
18
|
-
|
19
|
-
|
26
|
+
def followers(klass)
|
27
|
+
klass = klass.to_s.singularize.camelize.constantize unless klass.is_a?(Class)
|
28
|
+
klass.joins("INNER JOIN follows ON follows.follower_id = #{klass.to_s.tableize}.id AND follows.follower_type = '#{klass.to_s}'").
|
29
|
+
where("follows.followable_type = '#{self.class.to_s}'").
|
30
|
+
where("follows.followable_id = #{self.id}")
|
20
31
|
end
|
21
32
|
end
|
22
33
|
end
|
23
|
-
end
|
34
|
+
end
|
@@ -1,32 +1,43 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
def is_follower?
|
4
|
+
false
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
1
9
|
module Socialization
|
2
10
|
module Follower
|
3
|
-
|
4
|
-
base.class_eval do
|
5
|
-
# A follow is the Follow record of self following a followable record.
|
6
|
-
has_many :follows, :as => :follower, :dependent => :destroy, :class_name => 'Follow'
|
11
|
+
extend ActiveSupport::Concern
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
13
|
+
included do
|
14
|
+
# A follow is the Follow record of self following a followable record.
|
15
|
+
has_many :follows, :as => :follower, :dependent => :destroy, :class_name => 'Follow'
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
Follow.create! :follower => self, :followable => followable
|
16
|
-
end
|
17
|
+
def is_follower?
|
18
|
+
true
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
def follow!(followable)
|
22
|
+
raise ArgumentError, "#{followable} is not followable!" unless followable.is_followable?
|
23
|
+
raise ArgumentError, "#{self} cannot follow itself!" unless self != followable
|
24
|
+
Follow.create!({ :follower => self, :followable => followable }, :without_protection => true)
|
25
|
+
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
def unfollow!(followable)
|
28
|
+
ff = followable.followings.where(:follower_type => self.class.to_s, :follower_id => self.id)
|
29
|
+
unless ff.empty?
|
30
|
+
ff.each { |f| f.destroy }
|
31
|
+
else
|
32
|
+
raise ActiveRecord::RecordNotFound
|
27
33
|
end
|
34
|
+
end
|
28
35
|
|
36
|
+
def follows?(followable)
|
37
|
+
raise ArgumentError, "#{followable} is not followable!" unless followable.is_followable?
|
38
|
+
!self.follows.where(:followable_type => followable.class.to_s, :followable_id => followable.id).empty?
|
29
39
|
end
|
40
|
+
|
30
41
|
end
|
31
42
|
end
|
32
|
-
end
|
43
|
+
end
|
data/lib/socialization/hello.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
%w{followable follower follow_store likeable liker like_store mentionable mentionner mention_store}.each do |f|
|
2
4
|
require "#{File.dirname(__FILE__)}/#{f}"
|
3
5
|
end
|
4
6
|
|
5
7
|
module Socialization
|
6
8
|
module Hello
|
7
|
-
|
8
|
-
klass.send(:extend, ClassMethods)
|
9
|
-
end
|
9
|
+
extend ActiveSupport::Concern
|
10
10
|
|
11
11
|
module ClassMethods
|
12
|
+
## Follow
|
12
13
|
def acts_as_follower(opts = nil)
|
13
14
|
include Socialization::Follower
|
14
15
|
end
|
@@ -21,6 +22,7 @@ module Socialization
|
|
21
22
|
include Socialization::FollowStore
|
22
23
|
end
|
23
24
|
|
25
|
+
## Like
|
24
26
|
def acts_as_liker(opts = nil)
|
25
27
|
include Socialization::Liker
|
26
28
|
end
|
@@ -32,6 +34,20 @@ module Socialization
|
|
32
34
|
def acts_as_like_store(opts = nil)
|
33
35
|
include Socialization::LikeStore
|
34
36
|
end
|
37
|
+
|
38
|
+
## Mention
|
39
|
+
def acts_as_mentionner(opts = nil)
|
40
|
+
include Socialization::Mentionner
|
41
|
+
end
|
42
|
+
|
43
|
+
def acts_as_mentionable(opts = nil)
|
44
|
+
include Socialization::Mentionable
|
45
|
+
end
|
46
|
+
|
47
|
+
def acts_as_mention_store(opts = nil)
|
48
|
+
include Socialization::MentionStore
|
49
|
+
end
|
50
|
+
|
35
51
|
end
|
36
52
|
end
|
37
|
-
end
|
53
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module Socialization
|
2
2
|
module LikeStore
|
3
|
-
|
4
|
-
base.class_eval do
|
5
|
-
belongs_to :liker, :polymorphic => true
|
6
|
-
belongs_to :likeable, :polymorphic => true
|
3
|
+
extend ActiveSupport::Concern
|
7
4
|
|
8
|
-
|
5
|
+
included do
|
6
|
+
belongs_to :liker, :polymorphic => true
|
7
|
+
belongs_to :likeable, :polymorphic => true
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
validates_uniqueness_of :likeable_type, :scope => [:likeable_id, :liker_type, :liker_id], :message => 'You cannot like the same thing twice.'
|
10
|
+
|
11
|
+
def self.human_attribute_name(*args); ''; end
|
12
12
|
end
|
13
13
|
end
|
14
|
-
end
|
14
|
+
end
|
@@ -1,23 +1,34 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
def is_likeable?
|
4
|
+
false
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
1
9
|
module Socialization
|
2
10
|
module Likeable
|
3
|
-
|
4
|
-
base.class_eval do
|
5
|
-
# A liking is the Like record of the liker liking self.
|
6
|
-
has_many :likings, :as => :likeable, :dependent => :destroy, :class_name => 'Like'
|
11
|
+
extend ActiveSupport::Concern
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
13
|
+
included do
|
14
|
+
# A liking is the Like record of the liker liking self.
|
15
|
+
has_many :likings, :as => :likeable, :dependent => :destroy, :class_name => 'Like'
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
def is_likeable?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def liked_by?(liker)
|
22
|
+
raise ArgumentError, "#{liker} is not a liker!" unless liker.is_liker?
|
23
|
+
!self.likings.where(:liker_type => liker.class.to_s, :liker_id => liker.id).empty?
|
24
|
+
end
|
16
25
|
|
17
|
-
|
18
|
-
|
19
|
-
|
26
|
+
def likers(klass)
|
27
|
+
klass = klass.to_s.singularize.camelize.constantize unless klass.is_a?(Class)
|
28
|
+
klass.joins("INNER JOIN likes ON likes.liker_id = #{klass.to_s.tableize}.id AND likes.liker_type = '#{klass.to_s}'").
|
29
|
+
where("likes.likeable_type = '#{self.class.to_s}'").
|
30
|
+
where("likes.likeable_id = #{self.id}")
|
20
31
|
end
|
21
32
|
end
|
22
33
|
end
|
23
|
-
end
|
34
|
+
end
|
data/lib/socialization/liker.rb
CHANGED
@@ -1,32 +1,47 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
def is_liker?
|
4
|
+
false
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
1
9
|
module Socialization
|
2
10
|
module Liker
|
3
|
-
|
4
|
-
base.class_eval do
|
5
|
-
# A like is the Like record of self liking a likeable record.
|
6
|
-
has_many :likes, :as => :liker, :dependent => :destroy, :class_name => 'Like'
|
11
|
+
extend ActiveSupport::Concern
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
13
|
+
included do
|
14
|
+
# A like is the Like record of self liking a likeable record.
|
15
|
+
has_many :likes, :as => :liker, :dependent => :destroy, :class_name => 'Like'
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
Like.create! :liker => self, :likeable => likeable
|
16
|
-
end
|
17
|
+
def is_liker?
|
18
|
+
true
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
def like!(likeable)
|
22
|
+
ensure_likeable!(likeable)
|
23
|
+
raise ArgumentError, "#{self} cannot like itself!" unless self != likeable
|
24
|
+
Like.create!({ :liker => self, :likeable => likeable }, :without_protection => true)
|
25
|
+
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
def unlike!(likeable)
|
28
|
+
ll = likeable.likings.where(:liker_type => self.class.to_s, :liker_id => self.id)
|
29
|
+
unless ll.empty?
|
30
|
+
ll.each { |l| l.destroy }
|
31
|
+
else
|
32
|
+
raise ActiveRecord::RecordNotFound
|
27
33
|
end
|
34
|
+
end
|
28
35
|
|
36
|
+
def likes?(likeable)
|
37
|
+
ensure_likeable!(likeable)
|
38
|
+
!self.likes.where(:likeable_type => likeable.class.to_s, :likeable_id => likeable.id).empty?
|
29
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def ensure_likeable!(likeable)
|
43
|
+
raise ArgumentError, "#{likeable} is not likeable!" unless likeable.is_likeable?
|
44
|
+
end
|
30
45
|
end
|
31
46
|
end
|
32
|
-
end
|
47
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Socialization
|
2
|
+
module MentionStore
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
belongs_to :mentionner, :polymorphic => true
|
7
|
+
belongs_to :mentionable, :polymorphic => true
|
8
|
+
|
9
|
+
validates_uniqueness_of :mentionable_type, :scope => [:mentionable_id, :mentionner_type, :mentionner_id], :message => 'You cannot mention the same thing twice in a given object.'
|
10
|
+
|
11
|
+
def self.human_attribute_name(*args); ''; end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
def is_mentionable?
|
4
|
+
false
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Socialization
|
10
|
+
module Mentionable
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
# A mentioning is the Mention record of describing the mention relationship between
|
15
|
+
# the mentionner and the mentionable (self).
|
16
|
+
has_many :mentionings, :as => :mentionable, :dependent => :destroy, :class_name => 'Mention'
|
17
|
+
|
18
|
+
def is_mentionable?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def mentioned_by?(mentionner)
|
23
|
+
raise ArgumentError, "#{mentionner} is not a mentionner!" unless mentionner.is_mentionner?
|
24
|
+
!self.mentionings.where(:mentionner_type => mentionner.class.to_s, :mentionner_id => mentionner.id).empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def mentionners(klass)
|
28
|
+
klass = klass.to_s.singularize.camelize.constantize unless klass.is_a?(Class)
|
29
|
+
klass.joins("INNER JOIN mentions ON mentions.mentionner_id = #{klass.to_s.tableize}.id AND mentions.mentionner_type = '#{klass.to_s}'").
|
30
|
+
where("mentions.mentionable_type = '#{self.class.to_s}'").
|
31
|
+
where("mentions.mentionable_id = #{self.id}")
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
def is_mentionner?
|
4
|
+
false
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Socialization
|
10
|
+
module Mentionner
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
# A mention is the Mention record (self) mentionning a mentionable record.
|
15
|
+
has_many :mentions, :as => :mentionner, :dependent => :destroy, :class_name => 'Mention'
|
16
|
+
|
17
|
+
def is_mentionner?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def mention!(mentionable)
|
22
|
+
ensure_mentionable!(mentionable)
|
23
|
+
Mention.create!({ :mentionner => self, :mentionable => mentionable }, :without_protection => true)
|
24
|
+
end
|
25
|
+
|
26
|
+
def unmention!(mentionable)
|
27
|
+
mm = mentionable.mentionings.where(:mentionner_type => self.class.to_s, :mentionner_id => self.id)
|
28
|
+
unless mm.empty?
|
29
|
+
mm.each { |m| m.destroy }
|
30
|
+
else
|
31
|
+
raise ActiveRecord::RecordNotFound
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def mentions?(mentionable)
|
36
|
+
ensure_mentionable!(mentionable)
|
37
|
+
!self.mentions.where(:mentionable_type => mentionable.class.to_s, :mentionable_id => mentionable.id).empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def ensure_mentionable!(mentionable)
|
42
|
+
raise ArgumentError, "#{mentionable} is not mentionable!" unless mentionable.is_mentionable?
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/test/follow_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__)+'/test_helper'
|
1
|
+
require File.expand_path(File.dirname(__FILE__))+'/test_helper'
|
2
2
|
|
3
3
|
class FollowTest < Test::Unit::TestCase
|
4
4
|
context "a Follower" do
|
@@ -6,8 +6,7 @@ class FollowTest < Test::Unit::TestCase
|
|
6
6
|
seed
|
7
7
|
end
|
8
8
|
|
9
|
-
should "
|
10
|
-
assert_equal true, @follower1.respond_to?(:is_follower?)
|
9
|
+
should "be follower" do
|
11
10
|
assert_equal true, @follower1.is_follower?
|
12
11
|
end
|
13
12
|
|
@@ -22,6 +21,20 @@ class FollowTest < Test::Unit::TestCase
|
|
22
21
|
assert @follower1.unfollow!(@followable1)
|
23
22
|
assert_equal false, @follower1.follows?(@followable1)
|
24
23
|
end
|
24
|
+
|
25
|
+
should "not be able to follow the same thing twice" do
|
26
|
+
assert @follower1.follow!(@followable1)
|
27
|
+
|
28
|
+
assert_raise ActiveRecord::RecordInvalid do
|
29
|
+
@follower1.follow!(@followable1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
should "not be able to unfollow something that is not followed" do
|
34
|
+
assert_raise ActiveRecord::RecordNotFound do
|
35
|
+
@follower1.unfollow!(@followable1)
|
36
|
+
end
|
37
|
+
end
|
25
38
|
end
|
26
39
|
|
27
40
|
context "a Followable" do
|
@@ -29,8 +42,7 @@ class FollowTest < Test::Unit::TestCase
|
|
29
42
|
seed
|
30
43
|
end
|
31
44
|
|
32
|
-
should "
|
33
|
-
assert_equal true, @followable1.respond_to?(:is_followable?)
|
45
|
+
should "be followable" do
|
34
46
|
assert_equal true, @followable1.is_followable?
|
35
47
|
end
|
36
48
|
|
@@ -42,7 +54,11 @@ class FollowTest < Test::Unit::TestCase
|
|
42
54
|
|
43
55
|
should "expose a list of its followers" do
|
44
56
|
Follow.create :follower => @follower1, :followable => @followable1
|
45
|
-
|
57
|
+
assert @followable1.followers(ImAFollower).is_a?(ActiveRecord::Relation)
|
58
|
+
assert_equal [@follower1], @followable1.followers(ImAFollower).all
|
59
|
+
|
60
|
+
assert_equal @followable1.followers(ImAFollower), @followable1.followers(:im_a_followers)
|
61
|
+
assert_equal @followable1.followers(ImAFollower), @followable1.followers("im_a_follower")
|
46
62
|
end
|
47
63
|
|
48
64
|
should "expose followings" do
|
@@ -77,6 +93,20 @@ class FollowTest < Test::Unit::TestCase
|
|
77
93
|
end
|
78
94
|
end
|
79
95
|
|
96
|
+
context "Virgin ActiveRecord::Base objects" do
|
97
|
+
setup do
|
98
|
+
@foo = Vanilla.new
|
99
|
+
end
|
100
|
+
|
101
|
+
should "not be follower" do
|
102
|
+
assert_equal false, @foo.is_follower?
|
103
|
+
end
|
104
|
+
|
105
|
+
should "not be followable" do
|
106
|
+
assert_equal false, @foo.is_followable?
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
80
110
|
def seed
|
81
111
|
@follower1 = ImAFollower.create
|
82
112
|
@follower2 = ImAFollower.create
|