power_of_friendship 1.0.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/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 MISERALIS
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'PowerOfFriendship'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rake/testtask'
23
+
24
+ Rake::TestTask.new(:test) do |t|
25
+ t.libs << 'lib'
26
+ t.libs << 'test'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
30
+
31
+
32
+ task default: :test
@@ -0,0 +1,9 @@
1
+ Description:
2
+ This generator creates a migration and model files for friendship representations.
3
+
4
+ Example:
5
+ rails generate friendship <Name of Friend Model, eg: User>
6
+
7
+ This will create:
8
+ friendship model
9
+ friendship migration
@@ -0,0 +1,53 @@
1
+ class FriendshipGenerator < Rails::Generators::NamedBase
2
+ include Rails::Generators::Migration
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ desc "Create a model and migration for friendship. NAME is the model you wish to have a friendship relationship."
6
+
7
+ def generate_migration
8
+ migration_template "friendship_migration.rb.erb", "db/migrate/#{migration_file_name}"
9
+ end
10
+
11
+ def generate_class
12
+ template "friendship_model.rb.erb", "app/models/#{model_filename}"
13
+ end
14
+
15
+
16
+
17
+ def migration_name
18
+ "create_#{name.underscore}_friendship"
19
+ end
20
+
21
+ def migration_file_name
22
+ "#{migration_name}.rb"
23
+ end
24
+
25
+ def migration_class_name
26
+ migration_name.camelize
27
+ end
28
+
29
+ def orig_class_name_und
30
+ "#{name.underscore.downcase}"
31
+ end
32
+ def orig_class_name_cam
33
+ "#{name.camelize}"
34
+ end
35
+
36
+ def table_name
37
+ ":#{orig_class_name_und}_friendships"
38
+ end
39
+
40
+ def class_name
41
+ "#{orig_class_name_cam}Friendship"
42
+ end
43
+
44
+ def model_filename
45
+ "#{orig_class_name_und}_friendship.rb"
46
+ end
47
+
48
+
49
+ def self.next_migration_number(path)
50
+ require 'rails/generators/active_record'
51
+ ActiveRecord::Generators::Base.next_migration_number path
52
+ end
53
+ end
@@ -0,0 +1,16 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration
2
+ def change
3
+ create_table <%= table_name %> do |t|
4
+ t.belongs_to :<%= orig_class_name_und %>, index: true
5
+ t.belongs_to :friend, index: true
6
+ t.boolean :pending, :default => true
7
+
8
+
9
+ t.timestamps
10
+
11
+ end
12
+
13
+ add_index <%= table_name %>, [:<%= orig_class_name_und %>_id, :friend_id], :unique => true
14
+
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+ belongs_to :<%= orig_class_name_und %>
3
+
4
+ belongs_to :friend,
5
+ :class_name => <%= orig_class_name_cam %> ,
6
+ :foreign_key => :friend_id
7
+
8
+
9
+ validates_presence_of :friend_id, :<%= orig_class_name_und %>_id
10
+ validates_uniqueness_of :<%= orig_class_name_und %>_id, :scope => :friend_id
11
+
12
+ def approved?
13
+ !self.pending
14
+ end
15
+
16
+ def pending?
17
+ self.pending
18
+ end
19
+ end
@@ -0,0 +1,254 @@
1
+ require 'squeel'
2
+
3
+ module PowerOfFriendship
4
+
5
+
6
+ module ActsAsFriend
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+
11
+ end
12
+
13
+ module ClassMethods
14
+ def act_as_friend(options = {})
15
+
16
+ def self.pow_name_und
17
+ self.name.underscore.downcase
18
+ end
19
+
20
+ def self.pow_friendship_model
21
+ "#{self.name}Friendship".constantize
22
+ end
23
+
24
+ def self.pow_friendship_table
25
+ "#{pow_name_und}_friendships"
26
+ end
27
+
28
+ def self.pow_model_id
29
+ "#{pow_name_und}_id".to_sym
30
+
31
+ end
32
+
33
+ has_many :friends,
34
+ through: :approved_friendships,
35
+ :source => :friend
36
+
37
+ has_many :approved_friendships,
38
+ ->(t) {where("#{t.pow_friendship_table}.pending" => false)},
39
+ :foreign_key => pow_model_id,
40
+ :class_name => pow_friendship_model
41
+
42
+
43
+ has_many :friendships,
44
+ foreign_key: pow_model_id,
45
+ class_name: pow_friendship_model,
46
+ dependent: :destroy
47
+
48
+ has_many :followers,
49
+ :through => :inverse_friendships,
50
+ source: pow_name_und
51
+
52
+ has_many :invited_friends,
53
+ :through => :invited_friendships,
54
+ source: :friend
55
+
56
+ has_many :invited_friendships,
57
+ ->(t) {where("#{t.pow_friendship_table}.pending" => true)},
58
+ :foreign_key => pow_model_id,
59
+ :class_name => pow_friendship_model
60
+
61
+
62
+ has_many :inverse_friendships,
63
+ :class_name => pow_friendship_model,
64
+ :foreign_key => :friend_id,
65
+ dependent: :destroy
66
+
67
+ has_many :inverse_followers,
68
+ :through => :friendships,
69
+ source: :friend
70
+
71
+ has_many :pending_friends,
72
+ ->(t) {where("#{t.pow_friendship_table}.pending" => true)},
73
+ :through => :pending_friendships,
74
+ source: pow_name_und
75
+
76
+ has_many :pending_friendships,
77
+ ->(t) {where("#{t.pow_friendship_table}.pending" => true)},
78
+ :foreign_key => :friend_id,
79
+ :class_name => pow_friendship_model
80
+
81
+
82
+ include PowerOfFriendship::ActsAsFriend::LocalInstanceMethods
83
+ end
84
+ end
85
+
86
+ module LocalInstanceMethods
87
+ def pow_name_und
88
+ self.class.pow_name_und
89
+ end
90
+
91
+ def pow_model_id
92
+ self.class.pow_model_id
93
+ end
94
+
95
+ def pow_friendship_model
96
+ self.class.pow_friendship_model
97
+ end
98
+
99
+ def pow_friendship_table
100
+ self.class.pow_friendship_table
101
+ end
102
+
103
+
104
+
105
+ def invite(friend)
106
+ return false if friend == self || find_any_friendship_with(friend)
107
+ friendship = pow_friendship_model.new( pow_model_id => self.id, :friend_id => friend.id, pending: true ).save
108
+ friendship
109
+ end
110
+
111
+ def approve(friend)
112
+ friendship = pow_friendship_model.where(pow_model_id => friend.id, :friend_id => self.id, pending: true).first
113
+ return false if friendship.nil?
114
+ if friendship.update_attribute(:pending, false)
115
+ create_complimentary_friendship friendship
116
+ true
117
+ else
118
+ false
119
+ end
120
+ end
121
+
122
+ def unfriend(friend)
123
+ friendship = self.find_any_friendship_with friend
124
+ return true if not friendship
125
+ friendship.destroy
126
+ self.destroy_complimentary_friendship friendship
127
+ end
128
+
129
+ def follow(model)
130
+ return true if self.invite(model)
131
+ return self.approve model
132
+ end
133
+
134
+ def unfollow(model)
135
+ followership = pow_friendship_model.where(pow_model_id => self.id, :friend_id => model.id).first
136
+ return true if not followership
137
+ followership.destroy
138
+
139
+ if followership.approved?
140
+ other_followership = find_friendship_complement followership
141
+ other_followership.pending = true
142
+ other_followership.save
143
+ end
144
+ return true
145
+ end
146
+
147
+ def friends_with?(model)
148
+ self.friends.include?(model)
149
+ end
150
+
151
+ def follows?(model)
152
+ self.inverse_followers.include?(model)
153
+ end
154
+
155
+ def followed_by?(model)
156
+ self.followers.include?(model)
157
+ end
158
+
159
+ def connected_with?(model)
160
+ find_any_friendship_with(model).present?
161
+ end
162
+
163
+ def invited_by?(model)
164
+ friendship = find_any_friendship_with(model)
165
+ return false if friendship.nil?
166
+ return friendship.send(pow_model_id) == model.id if friendship.pending == true
167
+ inverse_friendship = find_friendship_complement friendship
168
+ return friendship.send(pow_model_id) == model.id if friendship.created_at <= inverse_friendship.created_at
169
+ return inverse_friendship.send(pow_model_id) == model.id
170
+ end
171
+
172
+ def invited?(model)
173
+ friendship = pow_friendship_model.where(pow_model_id => self.id, :friend_id => model.id).first
174
+ return false if friendship.nil?
175
+ return friendship.friend_id == model.id if friendship.pending == true
176
+ inverse_friendship = find_friendship_complement friendship
177
+ return friendship.friend_id == model.id if friendship.created_at <= inverse_friendship.created_at
178
+ return inverse_friendship.friend_id == model.id
179
+ end
180
+
181
+ def suggested_friends
182
+ pow_model_id_column = pow_model_id # TODO figure out how to avoid this
183
+ table = pow_friendship_table # TODO figure out how to avoid this
184
+ self_table = "#{pow_name_und}s"
185
+
186
+ approved_friendships = pow_friendship_model.where{
187
+ ( __send__(pow_model_id_column) == my{id}) &
188
+ ( pending == false )
189
+ }
190
+
191
+ pending_friendships = pow_friendship_model.where{
192
+ ( ( __send__(pow_model_id_column) == my{id}) |
193
+ ( friend_id == my{id}) ) &
194
+ ( pending == true )
195
+ }
196
+
197
+ buddies_relations = pow_friendship_model.where{
198
+ ( __send__(pow_model_id_column).in(approved_friendships.select{friend_id} ) ) &
199
+ ( __send__(pow_model_id_column) != my{id} )
200
+ }
201
+
202
+ potential = self.class.where{
203
+ ( __send__(table).__send__(pow_model_id_column).in(buddies_relations.select{friend_id} ) ) &
204
+ ( __send__(table).pending == false) &
205
+ ( __send__(table).friend_id.in(approved_friendships.select{friend_id} ) ) &
206
+ ( __send__(table).__send__(pow_model_id_column) != my{id} ) &
207
+ ( __send__(table).__send__(pow_model_id_column).not_in(pending_friendships.select{ __send__(table).__send__(pow_model_id_column)} ) ) &
208
+ ( __send__(table).__send__(pow_model_id_column).not_in(pending_friendships.select{ __send__(table).friend_id} ) ) &
209
+ ( __send__(table).__send__(pow_model_id_column).not_in(approved_friendships.select{ __send__(table).friend_id} ) )
210
+
211
+ }.select{
212
+ ["#{self_table}.id", "#{self_table}.*", __send__(table).count.as(:jcount)]
213
+
214
+ }.joins(:friendships).group{
215
+ [__send__(table).__send__(pow_model_id_column), "#{self_table}.id"]
216
+
217
+ }.order("jcount DESC")
218
+
219
+ potential
220
+ end
221
+
222
+
223
+ def create_complimentary_friendship(friendship)
224
+ return false if friendship.pending?
225
+ return pow_friendship_model.create(pow_model_id => friendship.friend_id,
226
+ friend_id: friendship.send(pow_model_id), pending: false)
227
+ end
228
+
229
+ def destroy_complimentary_friendship(friendship)
230
+ return false if friendship.pending?
231
+ friendship_compliment = find_friendship_complement friendship
232
+ return friendship_compliment.destroy
233
+ end
234
+
235
+ def find_friendship_complement friendship
236
+ friendship = pow_friendship_model.where(pow_model_id => friendship.friend_id, :friend_id => friendship.send(pow_model_id)).first
237
+ end
238
+
239
+ def find_any_friendship_with(model)
240
+ pow_model_id_column = pow_model_id # TODO figure out how to avoid this
241
+ friendship = pow_friendship_model.where{
242
+ (( __send__(pow_model_id_column) == my{id} ) &
243
+ ( friend_id == my{model.id} )) |
244
+ (( __send__(pow_model_id_column) == my{model.id} ) &
245
+ ( friend_id == my{id} ))
246
+ }.order(created_at: :desc).first;
247
+
248
+ friendship
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ ActiveRecord::Base.send :include, PowerOfFriendship::ActsAsFriend
@@ -0,0 +1,3 @@
1
+ module PowerOfFriendship
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :power_of_friendship do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: power_of_friendship
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - miseralis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-01-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 4.1.7
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 4.1.7
30
+ - !ruby/object:Gem::Dependency
31
+ name: squeel
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: pg
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec-rails
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: factory_girl_rails
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - '='
84
+ - !ruby/object:Gem::Version
85
+ version: 4.2.0
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - '='
92
+ - !ruby/object:Gem::Version
93
+ version: 4.2.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: tzinfo-data
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Power of Friendship is a friendship library for Rails' Active Records.
111
+ It allows you to add Facebook style friendships and/or Twitter style followers to
112
+ any model.
113
+ email:
114
+ - me@miseralis.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - lib/generators/friendship/friendship_generator.rb
120
+ - lib/generators/friendship/templates/friendship_migration.rb.erb
121
+ - lib/generators/friendship/templates/friendship_model.rb.erb
122
+ - lib/generators/friendship/USAGE
123
+ - lib/power_of_friendship/version.rb
124
+ - lib/power_of_friendship.rb
125
+ - lib/tasks/power_of_friendship_tasks.rake
126
+ - MIT-LICENSE
127
+ - Rakefile
128
+ homepage: https://github.com/Miseralis/power_of_friendship
129
+ licenses:
130
+ - MIT
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 1.8.28
150
+ signing_key:
151
+ specification_version: 3
152
+ summary: Empower your models with the awesome power of friendship
153
+ test_files: []