likeable 0.0.1

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.
@@ -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