twrk-socialization 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +8 -0
  5. data/Appraisals +23 -0
  6. data/CHANGELOG.md +67 -0
  7. data/Gemfile +3 -0
  8. data/Guardfile +12 -0
  9. data/LICENSE +20 -0
  10. data/README.md +298 -0
  11. data/Rakefile +14 -0
  12. data/demo/.gitignore +15 -0
  13. data/demo/Gemfile +35 -0
  14. data/demo/README.rdoc +261 -0
  15. data/demo/Rakefile +7 -0
  16. data/demo/app/assets/images/rails.png +0 -0
  17. data/demo/app/assets/javascripts/application.js +15 -0
  18. data/demo/app/assets/stylesheets/application.css +13 -0
  19. data/demo/app/controllers/application_controller.rb +3 -0
  20. data/demo/app/helpers/application_helper.rb +2 -0
  21. data/demo/app/mailers/.gitkeep +0 -0
  22. data/demo/app/models/.gitkeep +0 -0
  23. data/demo/app/models/celebrity.rb +4 -0
  24. data/demo/app/models/comment.rb +5 -0
  25. data/demo/app/models/follow.rb +3 -0
  26. data/demo/app/models/like.rb +2 -0
  27. data/demo/app/models/mention.rb +2 -0
  28. data/demo/app/models/movie.rb +3 -0
  29. data/demo/app/models/user.rb +7 -0
  30. data/demo/app/views/layouts/application.html.erb +14 -0
  31. data/demo/config/application.rb +59 -0
  32. data/demo/config/boot.rb +6 -0
  33. data/demo/config/database.yml +25 -0
  34. data/demo/config/environment.rb +5 -0
  35. data/demo/config/environments/development.rb +37 -0
  36. data/demo/config/environments/production.rb +67 -0
  37. data/demo/config/environments/test.rb +37 -0
  38. data/demo/config/initializers/backtrace_silencers.rb +7 -0
  39. data/demo/config/initializers/inflections.rb +15 -0
  40. data/demo/config/initializers/mime_types.rb +5 -0
  41. data/demo/config/initializers/secret_token.rb +7 -0
  42. data/demo/config/initializers/session_store.rb +8 -0
  43. data/demo/config/initializers/wrap_parameters.rb +14 -0
  44. data/demo/config/locales/en.yml +5 -0
  45. data/demo/config/routes.rb +58 -0
  46. data/demo/config.ru +4 -0
  47. data/demo/db/migrate/20120115051222_create_users.rb +9 -0
  48. data/demo/db/migrate/20120115051234_create_movies.rb +9 -0
  49. data/demo/db/migrate/20120115051255_create_celebrities.rb +9 -0
  50. data/demo/db/migrate/20120115054646_create_follows.rb +14 -0
  51. data/demo/db/migrate/20120115054647_create_likes.rb +14 -0
  52. data/demo/db/migrate/20120221200644_create_mentions.rb +14 -0
  53. data/demo/db/migrate/20120221202703_create_comments.rb +9 -0
  54. data/demo/db/schema.rb +72 -0
  55. data/demo/db/seeds.rb +17 -0
  56. data/demo/lib/assets/.gitkeep +0 -0
  57. data/demo/lib/tasks/.gitkeep +0 -0
  58. data/demo/public/404.html +26 -0
  59. data/demo/public/422.html +26 -0
  60. data/demo/public/500.html +25 -0
  61. data/demo/public/favicon.ico +0 -0
  62. data/demo/public/index.html +204 -0
  63. data/demo/public/robots.txt +5 -0
  64. data/demo/script/rails +6 -0
  65. data/demo/test/fixtures/.gitkeep +0 -0
  66. data/demo/test/fixtures/celebrities.yml +7 -0
  67. data/demo/test/fixtures/movies.yml +7 -0
  68. data/demo/test/fixtures/users.yml +7 -0
  69. data/demo/test/functional/.gitkeep +0 -0
  70. data/demo/test/integration/.gitkeep +0 -0
  71. data/demo/test/performance/browsing_test.rb +12 -0
  72. data/demo/test/test_helper.rb +13 -0
  73. data/demo/test/unit/.gitkeep +0 -0
  74. data/demo/test/unit/celebrity_test.rb +7 -0
  75. data/demo/test/unit/movie_test.rb +7 -0
  76. data/demo/test/unit/user_test.rb +7 -0
  77. data/demo/vendor/assets/javascripts/.gitkeep +0 -0
  78. data/demo/vendor/assets/stylesheets/.gitkeep +0 -0
  79. data/demo/vendor/plugins/.gitkeep +0 -0
  80. data/init.rb +1 -0
  81. data/lib/generators/socialization/socialization_generator.rb +38 -0
  82. data/lib/generators/socialization/templates/active_record/migration_follows.rb +14 -0
  83. data/lib/generators/socialization/templates/active_record/migration_likes.rb +14 -0
  84. data/lib/generators/socialization/templates/active_record/migration_mentions.rb +14 -0
  85. data/lib/generators/socialization/templates/active_record/model_follow.rb +2 -0
  86. data/lib/generators/socialization/templates/active_record/model_like.rb +2 -0
  87. data/lib/generators/socialization/templates/active_record/model_mention.rb +2 -0
  88. data/lib/generators/socialization/templates/redis/model_follow.rb +2 -0
  89. data/lib/generators/socialization/templates/redis/model_like.rb +2 -0
  90. data/lib/generators/socialization/templates/redis/model_mention.rb +2 -0
  91. data/lib/socialization/actors/follower.rb +88 -0
  92. data/lib/socialization/actors/liker.rb +88 -0
  93. data/lib/socialization/actors/mentioner.rb +88 -0
  94. data/lib/socialization/config/config.rb +39 -0
  95. data/lib/socialization/helpers/acts_as_helpers.rb +39 -0
  96. data/lib/socialization/helpers/string.rb +17 -0
  97. data/lib/socialization/lib/exceptions.rb +3 -0
  98. data/lib/socialization/stores/active_record/follow.rb +125 -0
  99. data/lib/socialization/stores/active_record/like.rb +121 -0
  100. data/lib/socialization/stores/active_record/mention.rb +125 -0
  101. data/lib/socialization/stores/active_record/mixins/base.rb +12 -0
  102. data/lib/socialization/stores/mixins/base.rb +22 -0
  103. data/lib/socialization/stores/mixins/follow.rb +39 -0
  104. data/lib/socialization/stores/mixins/like.rb +40 -0
  105. data/lib/socialization/stores/mixins/mention.rb +40 -0
  106. data/lib/socialization/stores/redis/base.rb +125 -0
  107. data/lib/socialization/stores/redis/config.rb +11 -0
  108. data/lib/socialization/stores/redis/follow.rb +22 -0
  109. data/lib/socialization/stores/redis/like.rb +22 -0
  110. data/lib/socialization/stores/redis/mention.rb +22 -0
  111. data/lib/socialization/stores/redis/mixins/base.rb +8 -0
  112. data/lib/socialization/version.rb +3 -0
  113. data/lib/socialization/victims/followable.rb +50 -0
  114. data/lib/socialization/victims/likeable.rb +51 -0
  115. data/lib/socialization/victims/mentionable.rb +51 -0
  116. data/lib/socialization.rb +20 -0
  117. data/socialization.gemspec +32 -0
  118. data/spec/actors/follower_spec.rb +113 -0
  119. data/spec/actors/liker_spec.rb +105 -0
  120. data/spec/actors/mentioner_spec.rb +105 -0
  121. data/spec/spec_helper.rb +21 -0
  122. data/spec/spec_support/data_stores.rb +232 -0
  123. data/spec/spec_support/matchers.rb +54 -0
  124. data/spec/stores/active_record/follow_store_spec.rb +147 -0
  125. data/spec/stores/active_record/like_store_spec.rb +146 -0
  126. data/spec/stores/active_record/mention_store_spec.rb +148 -0
  127. data/spec/stores/active_record/mixins/base_spec.rb +25 -0
  128. data/spec/stores/redis/base_spec.rb +195 -0
  129. data/spec/stores/redis/config_spec.rb +28 -0
  130. data/spec/stores/redis/follow_store_spec.rb +26 -0
  131. data/spec/stores/redis/like_store_spec.rb +23 -0
  132. data/spec/stores/redis/mention_store_spec.rb +23 -0
  133. data/spec/string_spec.rb +13 -0
  134. data/spec/victims/followable_spec.rb +59 -0
  135. data/spec/victims/likeable_spec.rb +58 -0
  136. data/spec/victims/mentionable_spec.rb +59 -0
  137. data/spec/world_spec.rb +107 -0
  138. metadata +322 -0
@@ -0,0 +1,38 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ STORES = %w(active_record redis)
5
+
6
+ class SocializationGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ source_root File.expand_path(File.join('templates'), File.dirname(__FILE__))
9
+ class_option :store, :type => :string, :default => 'active_record', :description => "Type of datastore"
10
+
11
+ def self.next_migration_number(dirname)
12
+ if ActiveRecord::Base.timestamped_migrations
13
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
14
+ else
15
+ "%.3d" % (current_migration_number(dirname) + 1)
16
+ end
17
+ end
18
+
19
+ def create_migration_file
20
+ options[:store].downcase!
21
+ unless STORES.include?(options[:store])
22
+ puts "Invalid store '#{options[:store]}'. The following stores are valid: #{STORES.join(', ')}."
23
+ exit 1
24
+ end
25
+
26
+ copy_file "#{options[:store]}/model_follow.rb", 'app/models/follow.rb'
27
+ copy_file "#{options[:store]}/model_like.rb", 'app/models/like.rb'
28
+ copy_file "#{options[:store]}/model_mention.rb", 'app/models/mention.rb'
29
+
30
+ if options[:store] == 'active_record'
31
+ migration_template "#{options[:store]}/migration_follows.rb", 'db/migrate/create_follows.rb'
32
+ sleep 1 # wait a second to have a unique migration timestamp
33
+ migration_template "#{options[:store]}/migration_likes.rb", 'db/migrate/create_likes.rb'
34
+ sleep 1 # wait a second to have a unique migration timestamp
35
+ migration_template "#{options[:store]}/migration_mentions.rb", 'db/migrate/create_mentions.rb'
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ class CreateFollows < ActiveRecord::Migration
2
+ def change
3
+ create_table :follows do |t|
4
+ t.string :follower_type
5
+ t.integer :follower_id
6
+ t.string :followable_type
7
+ t.integer :followable_id
8
+ t.datetime :created_at
9
+ end
10
+
11
+ add_index :follows, ["follower_id", "follower_type"], :name => "fk_follows"
12
+ add_index :follows, ["followable_id", "followable_type"], :name => "fk_followables"
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ class CreateLikes < ActiveRecord::Migration
2
+ def change
3
+ create_table :likes do |t|
4
+ t.string :liker_type
5
+ t.integer :liker_id
6
+ t.string :likeable_type
7
+ t.integer :likeable_id
8
+ t.datetime :created_at
9
+ end
10
+
11
+ add_index :likes, ["liker_id", "liker_type"], :name => "fk_likes"
12
+ add_index :likes, ["likeable_id", "likeable_type"], :name => "fk_likeables"
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ class CreateMentions < ActiveRecord::Migration
2
+ def change
3
+ create_table :mentions do |t|
4
+ t.string :mentioner_type
5
+ t.integer :mentioner_id
6
+ t.string :mentionable_type
7
+ t.integer :mentionable_id
8
+ t.datetime :created_at
9
+ end
10
+
11
+ add_index :mentions, ["mentioner_id", "mentioner_type"], :name => "fk_mentions"
12
+ add_index :mentions, ["mentionable_id", "mentionable_type"], :name => "fk_mentionables"
13
+ end
14
+ end
@@ -0,0 +1,2 @@
1
+ class Follow < Socialization::ActiveRecordStores::Follow
2
+ end
@@ -0,0 +1,2 @@
1
+ class Like < Socialization::ActiveRecordStores::Like
2
+ end
@@ -0,0 +1,2 @@
1
+ class Mention < Socialization::ActiveRecordStores::Mention
2
+ end
@@ -0,0 +1,2 @@
1
+ class Follow < Socialization::RedisStores::Follow
2
+ end
@@ -0,0 +1,2 @@
1
+ class Like < Socialization::RedisStores::Like
2
+ end
@@ -0,0 +1,2 @@
1
+ class Mention < Socialization::RedisStores::Mention
2
+ end
@@ -0,0 +1,88 @@
1
+ module ActiveRecord
2
+ class Base
3
+ def is_follower?
4
+ false
5
+ end
6
+ alias follower? is_follower?
7
+ end
8
+ end
9
+
10
+ module Socialization
11
+ module Follower
12
+ extend ActiveSupport::Concern
13
+
14
+ included do
15
+ after_destroy { Socialization.follow_model.remove_followables(self) }
16
+
17
+ # Specifies if self can follow {Followable} objects.
18
+ #
19
+ # @return [Boolean]
20
+ def is_follower?
21
+ true
22
+ end
23
+ alias follower? is_follower?
24
+
25
+ # Create a new {Follow follow} relationship.
26
+ #
27
+ # @param [Followable] followable the object to be followed.
28
+ # @return [Boolean]
29
+ def follow!(followable)
30
+ raise Socialization::ArgumentError, "#{followable} is not followable!" unless followable.respond_to?(:is_followable?) && followable.is_followable?
31
+ Socialization.follow_model.follow!(self, followable)
32
+ end
33
+
34
+ # Delete a {Follow follow} relationship.
35
+ #
36
+ # @param [Followable] followable the object to unfollow.
37
+ # @return [Boolean]
38
+ def unfollow!(followable)
39
+ raise Socialization::ArgumentError, "#{followable} is not followable!" unless followable.respond_to?(:is_followable?) && followable.is_followable?
40
+ Socialization.follow_model.unfollow!(self, followable)
41
+ end
42
+
43
+ # Toggles a {Follow follow} relationship.
44
+ #
45
+ # @param [Followable] followable the object to follow/unfollow.
46
+ # @return [Boolean]
47
+ def toggle_follow!(followable)
48
+ raise Socialization::ArgumentError, "#{followable} is not followable!" unless followable.respond_to?(:is_followable?) && followable.is_followable?
49
+ if follows?(followable)
50
+ unfollow!(followable)
51
+ false
52
+ else
53
+ follow!(followable)
54
+ true
55
+ end
56
+ end
57
+
58
+ # Specifies if self follows a {Followable} object.
59
+ #
60
+ # @param [Followable] followable the {Followable} object to test against.
61
+ # @return [Boolean]
62
+ def follows?(followable)
63
+ raise Socialization::ArgumentError, "#{followable} is not followable!" unless followable.respond_to?(:is_followable?) && followable.is_followable?
64
+ Socialization.follow_model.follows?(self, followable)
65
+ end
66
+
67
+ # Returns all the followables of a certain type that are followed by self
68
+ #
69
+ # @params [Followable] klass the type of {Followable} you want
70
+ # @params [Hash] opts a hash of options
71
+ # @return [Array<Followable, Numeric>] An array of Followable objects or IDs
72
+ def followables(klass, opts = {})
73
+ Socialization.follow_model.followables(self, klass, opts)
74
+ end
75
+ alias :followees :followables
76
+
77
+ # Returns a relation for all the followables of a certain type that are followed by self
78
+ #
79
+ # @params [Followable] klass the type of {Followable} you want
80
+ # @params [Hash] opts a hash of options
81
+ # @return ActiveRecord::Relation
82
+ def followables_relation(klass, opts = {})
83
+ Socialization.follow_model.followables_relation(self, klass, opts)
84
+ end
85
+ alias :followees_relation :followables_relation
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,88 @@
1
+ module ActiveRecord
2
+ class Base
3
+ def is_liker?
4
+ false
5
+ end
6
+ alias liker? is_liker?
7
+ end
8
+ end
9
+
10
+ module Socialization
11
+ module Liker
12
+ extend ActiveSupport::Concern
13
+
14
+ included do
15
+ after_destroy { Socialization.like_model.remove_likeables(self) }
16
+
17
+ # Specifies if self can like {Likeable} objects.
18
+ #
19
+ # @return [Boolean]
20
+ def is_liker?
21
+ true
22
+ end
23
+ alias liker? is_liker?
24
+
25
+ # Create a new {Like like} relationship.
26
+ #
27
+ # @param [Likeable] likeable the object to be liked.
28
+ # @return [Boolean]
29
+ def like!(likeable)
30
+ raise Socialization::ArgumentError, "#{likeable} is not likeable!" unless likeable.respond_to?(:is_likeable?) && likeable.is_likeable?
31
+ Socialization.like_model.like!(self, likeable)
32
+ end
33
+
34
+ # Delete a {Like like} relationship.
35
+ #
36
+ # @param [Likeable] likeable the object to unlike.
37
+ # @return [Boolean]
38
+ def unlike!(likeable)
39
+ raise Socialization::ArgumentError, "#{likeable} is not likeable!" unless likeable.respond_to?(:is_likeable?) && likeable.is_likeable?
40
+ Socialization.like_model.unlike!(self, likeable)
41
+ end
42
+
43
+ # Toggles a {Like like} relationship.
44
+ #
45
+ # @param [Likeable] likeable the object to like/unlike.
46
+ # @return [Boolean]
47
+ def toggle_like!(likeable)
48
+ raise Socialization::ArgumentError, "#{likeable} is not likeable!" unless likeable.respond_to?(:is_likeable?) && likeable.is_likeable?
49
+ if likes?(likeable)
50
+ unlike!(likeable)
51
+ false
52
+ else
53
+ like!(likeable)
54
+ true
55
+ end
56
+ end
57
+
58
+ # Specifies if self likes a {Likeable} object.
59
+ #
60
+ # @param [Likeable] likeable the {Likeable} object to test against.
61
+ # @return [Boolean]
62
+ def likes?(likeable)
63
+ raise Socialization::ArgumentError, "#{likeable} is not likeable!" unless likeable.respond_to?(:is_likeable?) && likeable.is_likeable?
64
+ Socialization.like_model.likes?(self, likeable)
65
+ end
66
+
67
+ # Returns all the likeables of a certain type that are liked by self
68
+ #
69
+ # @params [Likeable] klass the type of {Likeable} you want
70
+ # @params [Hash] opts a hash of options
71
+ # @return [Array<Likeable, Numeric>] An array of Likeable objects or IDs
72
+ def likeables(klass, opts = {})
73
+ Socialization.like_model.likeables(self, klass, opts)
74
+ end
75
+ alias :likees :likeables
76
+
77
+ # Returns a relation for all the likeables of a certain type that are liked by self
78
+ #
79
+ # @params [Likeable] klass the type of {Likeable} you want
80
+ # @params [Hash] opts a hash of options
81
+ # @return ActiveRecord::Relation
82
+ def likeables_relation(klass, opts = {})
83
+ Socialization.like_model.likeables_relation(self, klass, opts)
84
+ end
85
+ alias :likees_relation :likeables_relation
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,88 @@
1
+ module ActiveRecord
2
+ class Base
3
+ def is_mentioner?
4
+ false
5
+ end
6
+ alias mentioner? is_mentioner?
7
+ end
8
+ end
9
+
10
+ module Socialization
11
+ module Mentioner
12
+ extend ActiveSupport::Concern
13
+
14
+ included do
15
+ after_destroy { Socialization.mention_model.remove_mentionables(self) }
16
+
17
+ # Specifies if self can mention {Mentionable} objects.
18
+ #
19
+ # @return [Boolean]
20
+ def is_mentioner?
21
+ true
22
+ end
23
+ alias mentioner? is_mentioner?
24
+
25
+ # Create a new {Mention mention} relationship.
26
+ #
27
+ # @param [Mentionable] mentionable the object to be mentioned.
28
+ # @return [Boolean]
29
+ def mention!(mentionable)
30
+ raise Socialization::ArgumentError, "#{mentionable} is not mentionable!" unless mentionable.respond_to?(:is_mentionable?) && mentionable.is_mentionable?
31
+ Socialization.mention_model.mention!(self, mentionable)
32
+ end
33
+
34
+ # Delete a {Mention mention} relationship.
35
+ #
36
+ # @param [Mentionable] mentionable the object to unmention.
37
+ # @return [Boolean]
38
+ def unmention!(mentionable)
39
+ raise Socialization::ArgumentError, "#{mentionable} is not mentionable!" unless mentionable.respond_to?(:is_mentionable?) && mentionable.is_mentionable?
40
+ Socialization.mention_model.unmention!(self, mentionable)
41
+ end
42
+
43
+ # Toggles a {Mention mention} relationship.
44
+ #
45
+ # @param [Mentionable] mentionable the object to mention/unmention.
46
+ # @return [Boolean]
47
+ def toggle_mention!(mentionable)
48
+ raise Socialization::ArgumentError, "#{mentionable} is not mentionable!" unless mentionable.respond_to?(:is_mentionable?) && mentionable.is_mentionable?
49
+ if mentions?(mentionable)
50
+ unmention!(mentionable)
51
+ false
52
+ else
53
+ mention!(mentionable)
54
+ true
55
+ end
56
+ end
57
+
58
+ # Specifies if self mentions a {Mentionable} object.
59
+ #
60
+ # @param [Mentionable] mentionable the {Mentionable} object to test against.
61
+ # @return [Boolean]
62
+ def mentions?(mentionable)
63
+ raise Socialization::ArgumentError, "#{mentionable} is not mentionable!" unless mentionable.respond_to?(:is_mentionable?) && mentionable.is_mentionable?
64
+ Socialization.mention_model.mentions?(self, mentionable)
65
+ end
66
+
67
+ # Returns all the mentionables of a certain type that are mentioned by self
68
+ #
69
+ # @params [Mentionable] klass the type of {Mentionable} you want
70
+ # @params [Hash] opts a hash of options
71
+ # @return [Array<Mentionable, Numeric>] An array of Mentionable objects or IDs
72
+ def mentionables(klass, opts = {})
73
+ Socialization.mention_model.mentionables(self, klass, opts)
74
+ end
75
+ alias :mentionees :mentionables
76
+
77
+ # Returns a relation for all the mentionables of a certain type that are mentioned by self
78
+ #
79
+ # @params [Mentionable] klass the type of {Mentionable} you want
80
+ # @params [Hash] opts a hash of options
81
+ # @return ActiveRecord::Relation
82
+ def mentionables_relation(klass, opts = {})
83
+ Socialization.mention_model.mentionables_relation(self, klass, opts)
84
+ end
85
+ alias :mentionees_relation :mentionables_relation
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,39 @@
1
+ module Socialization
2
+ class << self
3
+ def follow_model
4
+ if @follow_model
5
+ @follow_model
6
+ else
7
+ ::Follow
8
+ end
9
+ end
10
+
11
+ def follow_model=(klass)
12
+ @follow_model = klass
13
+ end
14
+
15
+ def like_model
16
+ if @like_model
17
+ @like_model
18
+ else
19
+ ::Like
20
+ end
21
+ end
22
+
23
+ def like_model=(klass)
24
+ @like_model = klass
25
+ end
26
+
27
+ def mention_model
28
+ if @mention_model
29
+ @mention_model
30
+ else
31
+ ::Mention
32
+ end
33
+ end
34
+
35
+ def mention_model=(klass)
36
+ @mention_model = klass
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ require 'active_support/concern'
2
+
3
+ module Socialization
4
+ module ActsAsHelpers
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ # Make the current class a {Socialization::Follower}
9
+ def acts_as_follower(opts = {})
10
+ include Socialization::Follower
11
+ end
12
+
13
+ # Make the current class a {Socialization::Followable}
14
+ def acts_as_followable(opts = {})
15
+ include Socialization::Followable
16
+ end
17
+
18
+ # Make the current class a {Socialization::Liker}
19
+ def acts_as_liker(opts = {})
20
+ include Socialization::Liker
21
+ end
22
+
23
+ # Make the current class a {Socialization::Likeable}
24
+ def acts_as_likeable(opts = {})
25
+ include Socialization::Likeable
26
+ end
27
+
28
+ # Make the current class a {Socialization::Mentioner}
29
+ def acts_as_mentioner(opts = {})
30
+ include Socialization::Mentioner
31
+ end
32
+
33
+ # Make the current class a {Socialization::Mentionable}
34
+ def acts_as_mentionable(opts = {})
35
+ include Socialization::Mentionable
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ class String
2
+
3
+ def deep_const_get
4
+ result = nil
5
+ path = self.clone.split("::")
6
+
7
+ path.each do |p|
8
+ result = (result || Kernel).const_get(p)
9
+ end
10
+ result
11
+ end
12
+
13
+ def is_integer?
14
+ self.to_i.to_s == self
15
+ end
16
+
17
+ end
@@ -0,0 +1,3 @@
1
+ module Socialization
2
+ class ArgumentError < ::ArgumentError; end
3
+ end
@@ -0,0 +1,125 @@
1
+ module Socialization
2
+ module ActiveRecordStores
3
+ class Follow < ActiveRecord::Base
4
+ extend Socialization::Stores::Mixins::Base
5
+ extend Socialization::Stores::Mixins::Follow
6
+ extend Socialization::ActiveRecordStores::Mixins::Base
7
+
8
+ belongs_to :follower, :polymorphic => true
9
+ belongs_to :followable, :polymorphic => true
10
+
11
+ scope :followed_by, lambda { |follower| where(
12
+ :follower_type => follower.class.table_name.classify,
13
+ :follower_id => follower.id)
14
+ }
15
+
16
+ scope :following, lambda { |followable| where(
17
+ :followable_type => followable.class.table_name.classify,
18
+ :followable_id => followable.id)
19
+ }
20
+
21
+ class << self
22
+ def follow!(follower, followable)
23
+ unless follows?(follower, followable)
24
+ self.create! do |follow|
25
+ follow.follower = follower
26
+ follow.followable = followable
27
+ end
28
+ update_counter(follower, followees_count: +1)
29
+ update_counter(followable, followers_count: +1)
30
+ call_after_create_hooks(follower, followable)
31
+ true
32
+ else
33
+ false
34
+ end
35
+ end
36
+
37
+ def unfollow!(follower, followable)
38
+ if follows?(follower, followable)
39
+ follow_for(follower, followable).destroy_all
40
+ update_counter(follower, followees_count: -1)
41
+ update_counter(followable, followers_count: -1)
42
+ call_after_destroy_hooks(follower, followable)
43
+ true
44
+ else
45
+ false
46
+ end
47
+ end
48
+
49
+ def follows?(follower, followable)
50
+ !follow_for(follower, followable).empty?
51
+ end
52
+
53
+ # Returns an ActiveRecord::Relation of all the followers of a certain type that are following followable
54
+ def followers_relation(followable, klass, opts = {})
55
+ rel = klass.where(:id =>
56
+ self.select(:follower_id).
57
+ where(:follower_type => klass.table_name.classify).
58
+ where(:followable_type => followable.class.to_s).
59
+ where(:followable_id => followable.id)
60
+ )
61
+
62
+ if opts[:pluck]
63
+ rel.pluck(opts[:pluck])
64
+ else
65
+ rel
66
+ end
67
+ end
68
+
69
+ # Returns all the followers of a certain type that are following followable
70
+ def followers(followable, klass, opts = {})
71
+ rel = followers_relation(followable, klass, opts)
72
+ if rel.is_a?(ActiveRecord::Relation)
73
+ rel.to_a
74
+ else
75
+ rel
76
+ end
77
+ end
78
+
79
+ # Returns an ActiveRecord::Relation of all the followables of a certain type that are followed by follower
80
+ def followables_relation(follower, klass, opts = {})
81
+ rel = klass.where(:id =>
82
+ self.select(:followable_id).
83
+ where(:followable_type => klass.table_name.classify).
84
+ where(:follower_type => follower.class.to_s).
85
+ where(:follower_id => follower.id)
86
+ )
87
+
88
+ if opts[:pluck]
89
+ rel.pluck(opts[:pluck])
90
+ else
91
+ rel
92
+ end
93
+ end
94
+
95
+ # Returns all the followables of a certain type that are followed by follower
96
+ def followables(follower, klass, opts = {})
97
+ rel = followables_relation(follower, klass, opts)
98
+ if rel.is_a?(ActiveRecord::Relation)
99
+ rel.to_a
100
+ else
101
+ rel
102
+ end
103
+ end
104
+
105
+ # Remove all the followers for followable
106
+ def remove_followers(followable)
107
+ self.where(:followable_type => followable.class.name.classify).
108
+ where(:followable_id => followable.id).destroy_all
109
+ end
110
+
111
+ # Remove all the followables for follower
112
+ def remove_followables(follower)
113
+ self.where(:follower_type => follower.class.name.classify).
114
+ where(:follower_id => follower.id).destroy_all
115
+ end
116
+
117
+ private
118
+ def follow_for(follower, followable)
119
+ followed_by(follower).following(followable)
120
+ end
121
+ end # class << self
122
+
123
+ end
124
+ end
125
+ end