likeable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ require 'autotest/growl'
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format nested
2
+ --color
data/.rvmrc ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ruby_string="ree"
4
+ gemset_name="likeable"
5
+
6
+ if rvm list strings | grep -q "${ruby_string}" ; then
7
+
8
+ rvm use "${ruby_string}@${gemset_name}" --create
9
+
10
+ # Complain if bundler isn't installed
11
+ if [[ -z "`gem which bundler 2>&1 | grep -v ERROR`" ]]; then
12
+ echo "You need bundler:"
13
+ echo ""
14
+ echo " gem install bundler"
15
+ echo ""
16
+ fi
17
+ else
18
+ echo "${ruby_string} was not found, please run 'rvm install ${ruby_string}' and then cd back into the project directory."
19
+ fi
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'http://rubygems.org'
2
+ gem 'activesupport'
3
+ gem 'keytar', '>=1.5.2'
4
+ gem 'redis'
5
+
6
+
7
+ group :development, :test do
8
+ gem 'activerecord', '~>3.0.4' ## not needed if you're just using KeyBuilder
9
+ gem 'rake', '~>0.8.7'
10
+ gem 'jeweler', '~>1.5.2'
11
+ gem "autotest-standalone"
12
+ gem "autotest-growl"
13
+ end
14
+
15
+ group :test do
16
+ gem 'sqlite3', '~> 1.3.3'
17
+ gem 'rspec', '~> 2.5'
18
+ end
@@ -0,0 +1,108 @@
1
+ Use Redis to Make your Ruby objects Likeable!
2
+ ======
3
+
4
+ You like this
5
+ -------------
6
+ Likeable is the easiest way to allow your models to be liked by users, just drop a few lines of code into your model and you're good to go.
7
+
8
+ ```ruby
9
+
10
+ class Comment
11
+ include Likeable
12
+
13
+ # ...
14
+ end
15
+
16
+ class User
17
+ include Likeable::UserMethods
18
+
19
+ # ...
20
+ end
21
+
22
+ Likeable.setup do |likeable|
23
+ likeable.redis = Redis.new
24
+ end
25
+
26
+ comment = Comment.find(15)
27
+ comment.like_count # => 0
28
+ current_user.like!(comment) # => #<Likeable::Like ... >
29
+ comment.like_count # => 1
30
+ comment.likes # => [#<Likeable::Like ... >]
31
+ comment.likes.last.user # => #<User ... >
32
+ comment.likes.last.created_at # => Wed Jul 27 19:34:32 -0500 2011
33
+
34
+ comment.liked_by?(current_user) # => true
35
+
36
+ current_user.all_liked(Comment) # => [#<Comment ...>, ...]
37
+ ```
38
+
39
+
40
+ Setup
41
+ =======
42
+ Gemfile:
43
+
44
+ gem 'Likeable'
45
+
46
+ Next set up your Redis connection in initializers/likeable.rb:
47
+
48
+ ```ruby
49
+
50
+ Likeable.setup do |likeable|
51
+ likeable.redis = Redis.new
52
+ end
53
+ ```
54
+
55
+ Then add the `Likeable::UserMethods` module to models/user.rb:
56
+
57
+ ```ruby
58
+
59
+ class User
60
+ include Likeable::UserMethods
61
+ end
62
+ ```
63
+
64
+ Finally add `Likeable` module to any model you want to be liked:
65
+
66
+ ```ruby
67
+
68
+ class Comment
69
+ include Likeable
70
+ end
71
+ ```
72
+
73
+
74
+ Thats about it.
75
+
76
+ RedisRed RedisRedi
77
+ RedisRedisRedi RedisRedisRedisR
78
+ RedisRedisRedisRedi RedisRedisRedisRedi
79
+ RedisRedisRedisRedisRedisRedisRe Redi
80
+ RedisRedisRedisRedisRedisRedisRe Redi
81
+ RedisRedisRedisRedisRedisRedisRedisR Redi
82
+ RedisRedisRedisRedisRedisRedisRedisRedis R
83
+ RedisRedisRedisRedisRedisRedisRedisRedisRedi Red
84
+ RedisRedisRedisRedisRedisRedisRedisRedisRedisRe R
85
+ RedisRedisRedisRedisRedisRedisRedisRedisRedisRedi
86
+ RedisRedisRedisRedisRedisRedisRedisRedisRedisRedi
87
+ RedisRedisRedisRedisRedisRedisRedisRedisRedisRe
88
+ RedisRedisRedisRedisRedisRedisRedisRedisRedis
89
+ RedisRedisRedisRedisRedisRedisRedisRedisRe
90
+ RedisRedisRedisRedisRedisRedisRedisRe
91
+ RedisRedisRedisRedisRedisRedisR
92
+ RedisRedisRedisRedisRedis
93
+ RedisRedisRedisRedis
94
+ RedisRedisRed
95
+ RedisRedi
96
+ RedisR
97
+ Redi
98
+ Re
99
+
100
+ Contribution
101
+ ============
102
+
103
+ Fork away. If you want to chat about a feature idea, or a question you can find me on the twitters [@schneems](http://twitter.com/schneems). Put any major changes into feature branches. Make sure all tests stay green, and make sure your changes are covered.
104
+
105
+
106
+ licensed under MIT License
107
+ Copyright (c) 2011 Schneems. See LICENSE.txt for
108
+ further details.
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "likeable"
16
+ gem.homepage = "http://github.com/Schnems/likeable"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Like ruby objects backed by redis}
19
+ gem.description = %Q{
20
+ Likeable allows you to make your models...well...likeable using redis.
21
+ }
22
+ gem.email = "richard.schneeman@gmail.com"
23
+ gem.authors = ["Schneems"]
24
+ gem.add_development_dependency "rspec"
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
Binary file
@@ -0,0 +1,115 @@
1
+ require 'active_support/concern'
2
+ require 'keytar'
3
+
4
+
5
+ module Likeable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include Keytar
10
+ include Likeable::Facepile
11
+ define_key :like, :key_case => nil
12
+
13
+ if self.respond_to?(:after_destroy)
14
+ after_destroy :destroy_all_likes
15
+ else
16
+ warn "#{self} doesn't support after_destroy callback, likes will not be cleared automatically when object is destroyed"
17
+ end
18
+ end
19
+
20
+ def destroy_all_likes
21
+ liked_users.each {|user| self.remove_like_from(user) }
22
+ end
23
+
24
+ # create a like
25
+ # the user who created the like has a reference to the object liked
26
+ def add_like_from(user, time = Time.now.to_f)
27
+ Likeable.redis.hset(like_key, user.id, time)
28
+ Likeable.redis.hset(user.like_key(self.class.to_s.downcase), self.id, time)
29
+ like = Like.new(:target => self, :user => user, :time => time)
30
+ after_like(like)
31
+ clear_memoized_methods(:like_count, :like_user_ids, :liked_user_ids, :liked_users, :likes)
32
+ like
33
+ end
34
+
35
+ def clear_memoized_methods(*methods)
36
+ methods.each do |method|
37
+ eval("@#{method} = nil")
38
+ end
39
+ end
40
+
41
+ def after_like(like)
42
+ Likeable.after_like.call(like)
43
+ end
44
+
45
+ # removes a like
46
+ def remove_like_from(user)
47
+ Likeable.redis.hdel(like_key, user.id)
48
+ Likeable.redis.hdel(user.like_key(self.class.to_s.downcase), self.id)
49
+ clear_memoized_methods(:like_count, :like_user_ids, :liked_user_ids, :liked_users)
50
+ end
51
+
52
+ def like_count
53
+ @like_count ||= @like_user_ids.try(:count) || @likes.try(:count) || Likeable.redis.hlen(like_key)
54
+ end
55
+
56
+ # get all user ids that have liked a target object
57
+ def like_user_ids
58
+ @like_user_ids ||= (Likeable.redis.hkeys(like_key)||[]).map(&:to_i)
59
+ end
60
+
61
+ def liked_users(limit = nil)
62
+ @liked_users ||= User.where(:id => like_user_ids)
63
+ end
64
+
65
+ def likes
66
+ @likes ||= begin
67
+ Likeable.redis.hgetall(like_key).collect do |user_id, time|
68
+ Like.new(:user_id => user_id, :time => time, :target => self)
69
+ end
70
+ end
71
+ end
72
+
73
+ # did given user like the object
74
+ def liked_by?(user)
75
+ return false unless user
76
+ liked_by = @like_user_ids.include?(user.id) if @like_user_ids
77
+ liked_by ||= Likeable.redis.hexists(like_key, user.id)
78
+ end
79
+
80
+
81
+ def likeable_resource_name
82
+ Likeable.get_resource_name_for_class(self.class)
83
+ end
84
+
85
+
86
+ ### Class Methods ###
87
+ # ----------------- #
88
+ # allows us to setup callbacks when creating likes
89
+ # after_like :notify_users
90
+ module ClassMethods
91
+
92
+ def all_liked_ids_by(user)
93
+ key = user.like_key(self.to_s.downcase)
94
+ ids = (Likeable.redis.hkeys(key)||[]).map(&:to_i)
95
+ end
96
+
97
+ def all_liked_by(user)
98
+ ids = all_liked_ids_by(user)
99
+ self.where(:id => ids)
100
+ end
101
+
102
+ def after_like(*methods)
103
+ define_method(:after_like) do |like|
104
+ methods.each do |method|
105
+ eval("#{method}(like)")
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ require 'likeable/like'
113
+ require 'likeable/facepile'
114
+ require 'likeable/user_methods'
115
+ require 'likeable/module_methods'
@@ -0,0 +1,27 @@
1
+ module Likeable
2
+ module Facepile
3
+ # returns friend of user who like target
4
+ def liked_friends(user, limit = nil)
5
+ friend_ids = liked_friend_ids(user)
6
+ friend_ids = friend_ids.sample(limit) unless limit.blank?
7
+ @liked_friends ||= Likeable.find_many(User, friend_ids)
8
+ end
9
+
10
+ def liked_friend_ids(user)
11
+ @liked_friend_ids ||= like_user_ids & user.friend_ids
12
+ end
13
+
14
+ def ids_for_facepile(user, limit = Likeable.facepile_default_limit)
15
+ ids = liked_friend_ids(user).shuffle + like_user_ids.shuffle # show friends first
16
+ ids.uniq.first(limit)
17
+ end
18
+
19
+ def users_for_facepile(user, limit = Likeable.facepile_default_limit)
20
+ return [] if user.blank?
21
+ @facepile ||= begin
22
+ return nil unless ids = ids_for_facepile(user, limit)
23
+ Likeable.find_many(User, ids)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ require 'digest/sha1'
2
+
3
+ class Likeable::Like
4
+ attr_accessor :created_at, :target, :like_user, :user_id
5
+
6
+ def initialize(options = {})
7
+ self.created_at = Time.at(options[:time].try(:to_f)||Time.now)
8
+ self.target = options[:target]
9
+ self.user_id = options[:user].try(:id) || options[:user_id]
10
+ self.like_user = options[:user]
11
+ end
12
+
13
+ def id
14
+ Digest::SHA1.hexdigest("#{user_id}#{target.class}#{target.id}#{created_at}")
15
+ end
16
+
17
+ def user
18
+ @user ||= like_user
19
+ @user ||= Likeable.find_one(User, user_id)
20
+ @user
21
+ end
22
+
23
+ def to_hash(type=:full)
24
+ {
25
+ :created_at => created_at.iso8601,
26
+ :type => target.class.name.gsub(/^[A-Za-z]+::/, '').underscore.downcase.to_sym,
27
+ :target => target.to_hash(type),
28
+ :user => user.to_hash(type)
29
+ }
30
+ end
31
+ end
@@ -0,0 +1,133 @@
1
+ require 'redis'
2
+
3
+ module Likeable
4
+ mattr_accessor :facepile_default_limit
5
+ self.facepile_default_limit = 9
6
+
7
+
8
+ ### Module Methods ###
9
+ # ------------------ #
10
+ class << self
11
+ def classes
12
+ (@classes||[]).flatten
13
+ end
14
+
15
+ def classes=(*args)
16
+ @classes = args
17
+ end
18
+
19
+ # Likeable.model("Highlight")
20
+ # ------------------------- #
21
+ # turns a string into a model
22
+ # "Highlight".constantize # => Highlight; "Hi1i6ht".constantize = #=> false
23
+ def model(target_model)
24
+ target_model.camelcase.constantize
25
+ rescue NameError => ex
26
+ return false
27
+ end
28
+
29
+ # Likeable.find_by_resource_id("highlight", 22)
30
+ # ---------------------------------------- #
31
+ # #<Highlight id: ... # if highlight 22 exists
32
+ # nil # if highlight 22 does not exist
33
+ def find_by_resource_id(resource_name, target_id)
34
+ target = Likeable.get_class_for_resource_name(resource_name)
35
+ if target.present?
36
+ Likeable.find_one(target, target_id)
37
+ else
38
+ false
39
+ end
40
+ end
41
+
42
+ # Likeable.get_class_for_resource_name('photo')
43
+ # ------------------------- #
44
+ # Returns the class for the resource name
45
+ def get_class_for_resource_name(resource_name)
46
+ self.model(resource_name)
47
+ end
48
+
49
+ def get_resource_name_for_class(klass)
50
+ klass
51
+ end
52
+
53
+ def redis
54
+ @redis ||= Redis.new
55
+ end
56
+
57
+ def redis=(redis)
58
+ @redis = redis
59
+ end
60
+
61
+ def after_like(&block)
62
+ @after_like = block if block.present?
63
+ @after_like ||= lambda {}
64
+ @after_like
65
+ end
66
+
67
+ def find_many=(find_many)
68
+ @find_many = find_many
69
+ end
70
+
71
+ def find_many(klass, ids)
72
+ @find_many ||= lambda {|klass, ids| klass.where(:id => ids)}
73
+ @find_many.call(klass, ids)
74
+ end
75
+
76
+
77
+ def find_one(klass, id)
78
+ @find_one ||= lambda {|klass, ids| klass.where(:id => id)}
79
+ @find_one.call(klass, id)
80
+ end
81
+
82
+ def find_one=(find_one)
83
+ @find_one = find_one
84
+ end
85
+
86
+ def user_class
87
+ @user_class ||= ::User
88
+ end
89
+
90
+ def user_class=(user)
91
+ raise "User must be a class #{user.inspect}" unless user.class == Class
92
+ @user_class = user
93
+ end
94
+
95
+ # Likeable.setup do |like|
96
+ # like.redis = Redis.new(#...)
97
+ # like.find_one = lambda {|klass, id | klass.where(:id => id)}
98
+ # like.find_many = lambda {|klass, ids| klass.where(:id => ids)}
99
+ # like.classes = Spot, Comment
100
+ # end
101
+
102
+
103
+ def include_in_class(klass, include_item)
104
+ case
105
+ when defined?(Rails::Application)
106
+ Rails::Application.class_eval do
107
+ config.to_prepare do
108
+ klass.send :include, include_item
109
+ end
110
+ end
111
+ else
112
+ klass.send :include, include_item
113
+ end
114
+ end
115
+
116
+ def make_classes_likeable
117
+ classes.each do |klass|
118
+ include_in_class(klass, Likeable)
119
+ end
120
+ end
121
+
122
+ def give_users_like_ability
123
+ include_in_class user_class, ::Likeable::UserMethods
124
+ end
125
+
126
+ def setup(&block)
127
+ yield self unless block.blank?
128
+ make_classes_likeable
129
+ give_users_like_ability
130
+ true
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,36 @@
1
+ module Likeable::UserMethods
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ include Keytar
6
+ define_key :like, :key_case => nil
7
+ end
8
+
9
+
10
+ def like!(obj)
11
+ obj.add_like_from(self)
12
+ end
13
+
14
+ def unlike!(obj)
15
+ obj.remove_like_from(self)
16
+ end
17
+
18
+ def like?(obj)
19
+ obj.liked_by?(self)
20
+ end
21
+ alias :likes? :like?
22
+
23
+ def friend_ids_that_like(obj)
24
+ obj.liked_friend_ids(self)
25
+ end
26
+
27
+ def friends_that_like(obj, limit = nil)
28
+ obj.liked_friends(self, limit)
29
+ end
30
+
31
+ # @user.liked(Spot)
32
+ # will return all spots that user has liked
33
+ def all_liked(klass)
34
+ klass.all_liked_by(self)
35
+ end
36
+ end
@@ -0,0 +1,22 @@
1
+ licensed under MIT License:
2
+
3
+ Copyright (c) 2011 Schneems
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,94 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "likeable"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Schneems"]
12
+ s.date = "2011-10-12"
13
+ s.description = "\n Likeable allows you to make your models...well...likeable using redis.\n "
14
+ s.email = "richard.schneeman@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".autotest",
20
+ ".rspec",
21
+ ".rvmrc",
22
+ "Gemfile",
23
+ "README.md",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "autotest/discover.rb",
27
+ "lib/.DS_Store",
28
+ "lib/likeable.rb",
29
+ "lib/likeable/facepile.rb",
30
+ "lib/likeable/like.rb",
31
+ "lib/likeable/module_methods.rb",
32
+ "lib/likeable/user_methods.rb",
33
+ "license.txt",
34
+ "likeable.gemspec",
35
+ "spec/likeable/facepile_spec.rb",
36
+ "spec/likeable/like_spec.rb",
37
+ "spec/likeable/module_methods_spec.rb",
38
+ "spec/likeable/setup_spec.rb",
39
+ "spec/likeable/user_methods_spec.rb",
40
+ "spec/likeable_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = "http://github.com/Schnems/likeable"
44
+ s.licenses = ["MIT"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = "1.8.10"
47
+ s.summary = "Like ruby objects backed by redis"
48
+ s.test_files = [
49
+ "spec/likeable/facepile_spec.rb",
50
+ "spec/likeable/like_spec.rb",
51
+ "spec/likeable/module_methods_spec.rb",
52
+ "spec/likeable/setup_spec.rb",
53
+ "spec/likeable/user_methods_spec.rb",
54
+ "spec/likeable_spec.rb",
55
+ "spec/spec_helper.rb"
56
+ ]
57
+
58
+ if s.respond_to? :specification_version then
59
+ s.specification_version = 3
60
+
61
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
62
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
63
+ s.add_runtime_dependency(%q<keytar>, [">= 1.5.2"])
64
+ s.add_runtime_dependency(%q<redis>, [">= 0"])
65
+ s.add_development_dependency(%q<activerecord>, ["~> 3.0.4"])
66
+ s.add_development_dependency(%q<rake>, ["~> 0.8.7"])
67
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
68
+ s.add_development_dependency(%q<autotest-standalone>, [">= 0"])
69
+ s.add_development_dependency(%q<autotest-growl>, [">= 0"])
70
+ s.add_development_dependency(%q<rspec>, [">= 0"])
71
+ else
72
+ s.add_dependency(%q<activesupport>, [">= 0"])
73
+ s.add_dependency(%q<keytar>, [">= 1.5.2"])
74
+ s.add_dependency(%q<redis>, [">= 0"])
75
+ s.add_dependency(%q<activerecord>, ["~> 3.0.4"])
76
+ s.add_dependency(%q<rake>, ["~> 0.8.7"])
77
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
78
+ s.add_dependency(%q<autotest-standalone>, [">= 0"])
79
+ s.add_dependency(%q<autotest-growl>, [">= 0"])
80
+ s.add_dependency(%q<rspec>, [">= 0"])
81
+ end
82
+ else
83
+ s.add_dependency(%q<activesupport>, [">= 0"])
84
+ s.add_dependency(%q<keytar>, [">= 1.5.2"])
85
+ s.add_dependency(%q<redis>, [">= 0"])
86
+ s.add_dependency(%q<activerecord>, ["~> 3.0.4"])
87
+ s.add_dependency(%q<rake>, ["~> 0.8.7"])
88
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
89
+ s.add_dependency(%q<autotest-standalone>, [">= 0"])
90
+ s.add_dependency(%q<autotest-growl>, [">= 0"])
91
+ s.add_dependency(%q<rspec>, [">= 0"])
92
+ end
93
+ end
94
+
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ class CleanTestClassForLikeable
4
+ include Likeable
5
+ def like_key
6
+ "like_key"
7
+ end
8
+
9
+ def to_hash(*args); {} end
10
+
11
+ def foo
12
+ end
13
+
14
+ def id
15
+ @id ||= rand(100)
16
+ end
17
+ end
18
+
19
+
20
+ describe Likeable::Facepile do
21
+ before(:each) do
22
+ @user = User.new
23
+ @target = CleanTestClassForLikeable.new
24
+ end
25
+
26
+ describe 'facepile' do
27
+ before do
28
+ @friend_ids = [1,2,3,4]
29
+ @like_ids = [3,4,5,6,7,8,9,10,11,12]
30
+ @intersection = @friend_ids & @like_ids
31
+ end
32
+ describe '#ids_for_facepile' do
33
+ it 'builds a array of ids with friend ids and randoms if they have liked the object up to the limit' do
34
+ @target.should_receive(:liked_friend_ids).with(@user).and_return(@friend_ids)
35
+ @target.should_receive(:like_user_ids).and_return(@like_ids)
36
+ @target.ids_for_facepile(@user).should include(@intersection.sample)
37
+ end
38
+
39
+ it 'can be limited' do
40
+ limit = 3
41
+ @target.should_receive(:liked_friend_ids).and_return(@friend_ids)
42
+ @target.should_receive(:like_user_ids).and_return(@like_ids)
43
+ @target.ids_for_facepile(@user, limit).count.should eq(limit)
44
+ end
45
+ end
46
+
47
+ describe '#users_for_facepile' do
48
+ it 'builds a array of users if they have liked the object' do
49
+ @target.should_receive(:ids_for_facepile).and_return(@friend_ids)
50
+ User.should_receive(:where).with(:id => @friend_ids)
51
+ @target.users_for_facepile(@user)
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ describe Likeable::Like do
3
+ before do
4
+ @time = Time.now
5
+ end
6
+ describe 'attributes' do
7
+ it 'stores target, user, and created_at' do
8
+ like = Likeable::Like.new(:target => @target, :user => @user, :time => @time)
9
+ like.user.should eq(@user)
10
+ like.target.should eq(@target)
11
+ like.created_at.should eq(@time)
12
+ end
13
+
14
+ it 'converts float time to propper Time object' do
15
+ like = Likeable::Like.new(:time => @time.to_f)
16
+ like.created_at.should eq(@time)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ class CleanTestClassForLikeable
4
+ include Likeable
5
+ def like_key
6
+ "like_key"
7
+ end
8
+
9
+ def to_hash(*args); {} end
10
+
11
+ def foo
12
+ end
13
+
14
+ def id
15
+ @id ||= rand(100)
16
+ end
17
+ end
18
+
19
+ class LikeableIncludedInSetup
20
+ def like_key
21
+ "like_key"
22
+ end
23
+
24
+ def id
25
+ @id ||= rand(100)
26
+ end
27
+ end
28
+
29
+ describe Likeable::Facepile do
30
+ before(:each) do
31
+ @user = User.new
32
+ @target = CleanTestClassForLikeable.new
33
+ end
34
+
35
+ describe "module methods" do
36
+ describe ".model" do
37
+ it "takes a valid class string and turns it into a class" do
38
+ klass = CleanTestClassForLikeable
39
+ klass_name = klass.to_s
40
+ Likeable.model(klass_name).should eq(klass)
41
+ end
42
+ end
43
+
44
+ describe ".find_by_resource_id" do
45
+ it "finds an active-record based object on a valid model and id" do
46
+ klass = CleanTestClassForLikeable
47
+ klass_name = klass.to_s
48
+ id = rand(1000)
49
+ klass.should_receive(:where).with(:id => id).and_return([])
50
+ Likeable.find_by_resource_id(klass_name, id)
51
+ end
52
+
53
+ it "will return nil for an invalid object" do
54
+ klass = CleanTestClassForLikeable
55
+ klass_name = klass.to_s + "this makes this klass_name invalid"
56
+
57
+ Likeable.find_by_resource_id(klass_name, rand(1000)).should be_blank
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ class LikeableIncludedInSetup
5
+
6
+ end
7
+
8
+ class SetupCleanTestClassForLikeable
9
+ include Likeable
10
+ def like_key
11
+ "like_key"
12
+ end
13
+
14
+ def to_hash(*args); {} end
15
+
16
+ def foo
17
+ end
18
+
19
+ def id
20
+ @id ||= rand(100)
21
+ end
22
+ end
23
+
24
+ describe Likeable do
25
+ before(:each) do
26
+ reload_user!
27
+ Likeable.user_class = User
28
+ @user = User.new
29
+ @target = SetupCleanTestClassForLikeable.new
30
+ end
31
+
32
+
33
+ describe "Likeable setup" do
34
+ it "adds Likeable::UserMethods to User" do
35
+ describe User.ancestors do
36
+ it {should_not include Likeable::UserMethods}
37
+ end
38
+ Likeable.setup
39
+ describe User.ancestors do
40
+ it {should include Likeable::UserMethods}
41
+ end
42
+ end
43
+
44
+ it "adds likeable to class" do
45
+ Likeable.setup do |like|
46
+ like.classes = LikeableIncludedInSetup
47
+ end
48
+
49
+ describe LikeableIncludedInSetup.ancestors do
50
+ it {should include Likeable}
51
+ end
52
+ end
53
+
54
+ it "" do
55
+ result = "foo"
56
+ Likeable.setup
57
+
58
+ Likeable.after_like do |like|
59
+ result = "after_like_called_successfully"
60
+ end
61
+
62
+ @user.like! @target
63
+ result.should == "after_like_called_successfully"
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ class CleanTestClassForLikeable
4
+ include Likeable
5
+ def like_key
6
+ "like_key"
7
+ end
8
+
9
+ def to_hash(*args); {} end
10
+
11
+ def foo
12
+ end
13
+
14
+ def id
15
+ @id ||= rand(100)
16
+ end
17
+ end
18
+
19
+ Likeable.setup
20
+
21
+ describe Likeable::UserMethods do
22
+ before(:each) do
23
+ @user = User.new
24
+ @target = CleanTestClassForLikeable.new
25
+ end
26
+
27
+ describe '#like!' do
28
+ it "calls add_like_from in target" do
29
+ @target.should_receive(:add_like_from).with(@user)
30
+ @user.like! @target
31
+ end
32
+ end
33
+
34
+ describe '#unlike!' do
35
+ it "calls remove_like_from in target" do
36
+ @target.should_receive(:remove_like_from).with(@user)
37
+ @user.unlike! @target
38
+ end
39
+ end
40
+
41
+ describe '#like?' do
42
+ it "calls liked_by? in target" do
43
+ @target.should_receive(:liked_by?).with(@user)
44
+ @user.like? @target
45
+ end
46
+ end
47
+
48
+ describe '#like?' do
49
+ it "calls liked_by? in target" do
50
+ @target.should_receive(:liked_by?).with(@user)
51
+ @user.like? @target
52
+ end
53
+ end
54
+
55
+ describe '#friend_ids_that_like' do
56
+ it "calls liked_friend_ids? in target" do
57
+ @target.should_receive(:liked_friend_ids).with(@user)
58
+ @user.friend_ids_that_like @target
59
+ end
60
+ end
61
+
62
+ describe '#friends_that_like' do
63
+ it "calls liked_friends? in target" do
64
+ @target.should_receive(:liked_friends).with(@user, nil)
65
+ @user.friends_that_like @target
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+ class CleanTestClassForLikeable
3
+ include Likeable
4
+ def like_key
5
+ "like_key"
6
+ end
7
+
8
+ def to_hash(*args); {} end
9
+
10
+ def foo
11
+ end
12
+
13
+ def id
14
+ @id ||= rand(100)
15
+ end
16
+ end
17
+
18
+
19
+
20
+
21
+ Likeable.setup do |like|
22
+ like.find_one = lambda {|klass, id| klass.where(:id => id)}
23
+ end
24
+
25
+
26
+ describe Likeable do
27
+
28
+ before(:each) do
29
+ @user = User.new
30
+ @target = CleanTestClassForLikeable.new
31
+ end
32
+ describe 'instance methods' do
33
+
34
+ describe "#add_like_from" do
35
+ it "creates a like" do
36
+ target_class = @target.class.to_s.downcase
37
+ user_like_key = "users:like:#{@user.id}:#{target_class}"
38
+ time = Time.now.to_f
39
+ @user.should_receive(:like_key).with(target_class).and_return(user_like_key)
40
+ Likeable.redis.should_receive(:hset).with("like_key", @user.id, time).once
41
+ Likeable.redis.should_receive(:hset).with(user_like_key, @target.id, time).once
42
+ @target.add_like_from(@user, time)
43
+ end
44
+ end
45
+
46
+ describe "#remove_like_from" do
47
+ it "removes a like" do
48
+ target_class = @target.class.to_s.downcase
49
+ user_like_key = "users:like:#{@user.id}:#{target_class}"
50
+ @user.should_receive(:like_key).with(target_class).and_return(user_like_key)
51
+ Likeable.redis.should_receive(:hdel).with("like_key", @user.id).once
52
+ Likeable.redis.should_receive(:hdel).with(user_like_key, @target.id)
53
+ @target.remove_like_from(@user)
54
+ end
55
+ end
56
+
57
+ describe "#likes" do
58
+ it "returns set of likes" do
59
+ Likeable.redis.should_receive(:hkeys).with("like_key").once
60
+ @target.like_user_ids
61
+ end
62
+ end
63
+
64
+ describe "#liked_by?" do
65
+ it "will answer if current user likes target" do
66
+ Likeable.redis.should_receive(:hexists).with("like_key", @user.id).once
67
+ @target.liked_by?(@user)
68
+ end
69
+ end
70
+
71
+ describe "#liked_friend_ids" do
72
+ it "will return all friend ids of user who like target" do
73
+ common_value = 3
74
+ @target.should_receive(:like_user_ids).and_return([1,2, common_value])
75
+ @user.should_receive(:friend_ids).and_return([common_value])
76
+ @target.liked_friend_ids(@user).should == [common_value]
77
+ end
78
+ end
79
+
80
+ describe "#liked_friends" do
81
+ it "will return all friends who like object" do
82
+ values = [1]
83
+ @target.should_receive(:liked_friend_ids).with(@user).and_return(values)
84
+ User.should_receive(:where).with(:id => values)
85
+ @target.liked_friends(@user)
86
+ end
87
+ end
88
+ end
89
+
90
+ describe "class methods" do
91
+ describe 'after_like' do
92
+ it 'should be a class method when included' do
93
+ CleanTestClassForLikeable.respond_to?(:after_like).should be_true
94
+ end
95
+ it 'is called after a like is created' do
96
+ CleanTestClassForLikeable.after_like(:foo)
97
+ @target.should_receive(:foo)
98
+ @target.add_like_from(@user)
99
+ end
100
+ end
101
+ end
102
+
103
+ end
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '../..', 'lib'))
7
+
8
+
9
+ def build_user!
10
+ eval %Q{
11
+ class User
12
+ def id
13
+ @time ||= Time.now.to_f.to_s
14
+ end
15
+
16
+ def self.where(*args)
17
+ end
18
+
19
+ def friends_ids
20
+ []
21
+ end
22
+
23
+ def self.after_destroy
24
+ end
25
+ end
26
+ }
27
+ end
28
+
29
+ def unload_user!
30
+ Object.instance_eval{ remove_const :User }
31
+ end
32
+
33
+ def reload_user!
34
+ unload_user!
35
+ build_user!
36
+ end
37
+
38
+ build_user!
39
+
40
+ require 'likeable'
41
+
42
+ require 'rspec'
43
+ require 'rspec/autorun'
44
+
metadata ADDED
@@ -0,0 +1,226 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: likeable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Schneems
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-12 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ hash: 3
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ name: activesupport
31
+ prerelease: false
32
+ type: :runtime
33
+ requirement: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ version_requirements: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ hash: 7
41
+ segments:
42
+ - 1
43
+ - 5
44
+ - 2
45
+ version: 1.5.2
46
+ name: keytar
47
+ prerelease: false
48
+ type: :runtime
49
+ requirement: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ version_requirements: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ name: redis
61
+ prerelease: false
62
+ type: :runtime
63
+ requirement: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ version_requirements: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ hash: 15
71
+ segments:
72
+ - 3
73
+ - 0
74
+ - 4
75
+ version: 3.0.4
76
+ name: activerecord
77
+ prerelease: false
78
+ type: :development
79
+ requirement: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ version_requirements: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ hash: 49
87
+ segments:
88
+ - 0
89
+ - 8
90
+ - 7
91
+ version: 0.8.7
92
+ name: rake
93
+ prerelease: false
94
+ type: :development
95
+ requirement: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ version_requirements: &id006 !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ~>
101
+ - !ruby/object:Gem::Version
102
+ hash: 7
103
+ segments:
104
+ - 1
105
+ - 5
106
+ - 2
107
+ version: 1.5.2
108
+ name: jeweler
109
+ prerelease: false
110
+ type: :development
111
+ requirement: *id006
112
+ - !ruby/object:Gem::Dependency
113
+ version_requirements: &id007 !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ hash: 3
119
+ segments:
120
+ - 0
121
+ version: "0"
122
+ name: autotest-standalone
123
+ prerelease: false
124
+ type: :development
125
+ requirement: *id007
126
+ - !ruby/object:Gem::Dependency
127
+ version_requirements: &id008 !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ hash: 3
133
+ segments:
134
+ - 0
135
+ version: "0"
136
+ name: autotest-growl
137
+ prerelease: false
138
+ type: :development
139
+ requirement: *id008
140
+ - !ruby/object:Gem::Dependency
141
+ version_requirements: &id009 !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ hash: 3
147
+ segments:
148
+ - 0
149
+ version: "0"
150
+ name: rspec
151
+ prerelease: false
152
+ type: :development
153
+ requirement: *id009
154
+ description: "\n Likeable allows you to make your models...well...likeable using redis.\n "
155
+ email: richard.schneeman@gmail.com
156
+ executables: []
157
+
158
+ extensions: []
159
+
160
+ extra_rdoc_files:
161
+ - README.md
162
+ files:
163
+ - .autotest
164
+ - .rspec
165
+ - .rvmrc
166
+ - Gemfile
167
+ - README.md
168
+ - Rakefile
169
+ - VERSION
170
+ - autotest/discover.rb
171
+ - lib/.DS_Store
172
+ - lib/likeable.rb
173
+ - lib/likeable/facepile.rb
174
+ - lib/likeable/like.rb
175
+ - lib/likeable/module_methods.rb
176
+ - lib/likeable/user_methods.rb
177
+ - license.txt
178
+ - likeable.gemspec
179
+ - spec/likeable/facepile_spec.rb
180
+ - spec/likeable/like_spec.rb
181
+ - spec/likeable/module_methods_spec.rb
182
+ - spec/likeable/setup_spec.rb
183
+ - spec/likeable/user_methods_spec.rb
184
+ - spec/likeable_spec.rb
185
+ - spec/spec_helper.rb
186
+ homepage: http://github.com/Schnems/likeable
187
+ licenses:
188
+ - MIT
189
+ post_install_message:
190
+ rdoc_options: []
191
+
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ none: false
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ hash: 3
200
+ segments:
201
+ - 0
202
+ version: "0"
203
+ required_rubygems_version: !ruby/object:Gem::Requirement
204
+ none: false
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ hash: 3
209
+ segments:
210
+ - 0
211
+ version: "0"
212
+ requirements: []
213
+
214
+ rubyforge_project:
215
+ rubygems_version: 1.8.10
216
+ signing_key:
217
+ specification_version: 3
218
+ summary: Like ruby objects backed by redis
219
+ test_files:
220
+ - spec/likeable/facepile_spec.rb
221
+ - spec/likeable/like_spec.rb
222
+ - spec/likeable/module_methods_spec.rb
223
+ - spec/likeable/setup_spec.rb
224
+ - spec/likeable/user_methods_spec.rb
225
+ - spec/likeable_spec.rb
226
+ - spec/spec_helper.rb