horde-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in horde.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Dorren Chen
2
+
3
+ MIT License
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.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # Horde
2
+
3
+ Horde is a gem to help you implement social networking features in your app, like follow a user, favorite a photo, and comment on an article, etc.
4
+
5
+ ## Usage
6
+ Say your app has typical models like User, Article, Category, etc.
7
+
8
+ ```ruby
9
+ # ----- setup models
10
+ class User
11
+ include Horde::Actor
12
+
13
+ include Horde::Actions::Follow # allow one user follow another user
14
+ end
15
+
16
+ class Article
17
+ include Horde::Actions::All # all actions that can be performed on this model.
18
+
19
+ # or selectively, a few of them
20
+ # include Horde::Actions::Comment
21
+ # include Horde::Actions::Favorite
22
+ # include Horde::Actions::Follow
23
+ # include Horde::Actions::Rate
24
+ end
25
+
26
+ # ----- case 1: favoriting
27
+ favorite = user.favorite(article) # saved in 'horde_favorites' table
28
+ favorite.favoriter # --> user
29
+ favorite.target # --> article
30
+ favorite.favorited_article # --> same article
31
+
32
+ article.favorites # --> [favorite]
33
+ article.favoriters # --> [user]
34
+ user.created_favorites # --> [favorite], could point to any target, article, photo.
35
+ user.favorited_articles # --> [article], this user's favorited articles
36
+
37
+
38
+ # ----- case 2: commenting
39
+ comment = user.comment(article, :comment => 'luv it') # saved in 'horde_comments' table
40
+ comment.commenter # --> user
41
+ comment.target # --> article
42
+ comment.commented_article # --> same article
43
+
44
+ article.comments # --> [comment]
45
+ article.commenters # --> [user]
46
+ user.created_comments # --> [comment]
47
+ user.commented_articles # --> [article]
48
+
49
+
50
+ # ----- case 3: rating
51
+ rate = user.rate(article, :score => 10)
52
+ rate.rater # --> user
53
+ rate.target # --> article
54
+ rate.rated_article # --> same article
55
+
56
+ article.rates # --> [rate]
57
+ article.raters # --> [user]
58
+ user.created_rates # --> [rate]
59
+ user.rated_articles # --> [article]
60
+ ```
61
+
62
+ How do you notify commenters when new comment is posted for an article?
63
+ ```ruby
64
+ class Article
65
+ after_comment :notify_commenters
66
+ after_favorite :do_something
67
+ after_rate :do_something_else
68
+
69
+ def notify_commenters(comment)
70
+ msg = "#{comment.commenter.login} just commented on article '#{self.title}'"
71
+ emails = commenters.map &:email
72
+ # email all users
73
+ end
74
+ end
75
+ ```
76
+
77
+
78
+ ## Installation
79
+
80
+ Add this line to your application's Gemfile:
81
+
82
+ gem 'horde'
83
+
84
+ And then execute:
85
+
86
+ $ bundle
87
+
88
+ Or install it yourself as:
89
+
90
+ $ gem install horde
91
+
92
+
93
+ copy db/migrate/timestamp_horde_setup.rb to your app. I haven't figure
94
+ out how to use generator.
95
+
96
+
97
+ ## Contributing
98
+
99
+ 1. Fork it
100
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
101
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
102
+ 4. Push to the branch (`git push origin my-new-feature`)
103
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/setup'
3
+ require "bundler/gem_tasks"
4
+ require 'sinatra/activerecord/rake'
5
+
6
+ require "horde"
7
+ require_relative "spec/support/db_config"
@@ -0,0 +1,56 @@
1
+ class HordeSetup < ActiveRecord::Migration
2
+ def up
3
+ create_table :horde_favorites do |t|
4
+ t.string :actor_id, :limit => 64
5
+ t.string :target_type, :limit => 64
6
+ t.string :target_id, :limit => 64
7
+
8
+ t.timestamps
9
+ end
10
+ add_index :horde_favorites, :actor_id
11
+ add_index :horde_favorites, [:target_id, :target_type]
12
+
13
+
14
+ create_table :horde_follows do |t|
15
+ t.string :actor_id, :limit => 64
16
+ t.string :target_type, :limit => 64
17
+ t.string :target_id, :limit => 64
18
+
19
+ t.timestamps
20
+ end
21
+ add_index :horde_follows, :actor_id
22
+ add_index :horde_follows, [:target_id, :target_type]
23
+
24
+
25
+ create_table :horde_comments do |t|
26
+ t.string :actor_id, :limit => 64
27
+ t.string :target_type, :limit => 64
28
+ t.string :target_id, :limit => 64
29
+ t.string :comment, :limit => 2048
30
+ t.integer :abuse_count, :default => 0
31
+
32
+ t.timestamps
33
+ end
34
+ add_index :horde_comments, :actor_id
35
+ add_index :horde_comments, [:target_id, :target_type]
36
+ add_index :horde_comments, :abuse_count
37
+
38
+
39
+ create_table :horde_rates do |t|
40
+ t.string :actor_id, :limit => 64
41
+ t.string :target_type, :limit => 64
42
+ t.string :target_id, :limit => 64
43
+ t.integer :score
44
+
45
+ t.timestamps
46
+ end
47
+ add_index :horde_rates, :actor_id
48
+ add_index :horde_rates, [:target_id, :target_type]
49
+ end
50
+
51
+ def down
52
+ drop_table :horde_favorites
53
+ drop_table :horde_comments
54
+ drop_table :horde_rates
55
+ end
56
+ end
@@ -0,0 +1,33 @@
1
+ class TestModels < ActiveRecord::Migration
2
+ def up
3
+ create_table :users do |t|
4
+ t.string :login, :limit => 64
5
+ t.string :email, :limit => 64
6
+ t.string :first_name, :limit => 64
7
+ t.string :last_name, :limit => 64
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ create_table :articles do |t|
13
+ t.string :title
14
+ t.string :body
15
+ t.string :author_id
16
+
17
+ t.timestamps
18
+ end
19
+
20
+ create_table :photos do |t|
21
+ t.string :name
22
+ t.string :author_id
23
+
24
+ t.timestamps
25
+ end
26
+ end
27
+
28
+ def down
29
+ drop_table :users
30
+ drop_table :articles
31
+ drop_table :photos
32
+ end
33
+ end
data/horde.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/horde/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Dorren Chen"]
6
+ gem.email = ["dorrenchen@gmail.com"]
7
+ gem.description = %q{A ruby gem providing social networking features for rails app.}
8
+ gem.summary = %q{A ruby gem providing social networking features for rails app.}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "horde-rails"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Horde::VERSION
17
+
18
+ gem.add_dependency "mysql2"
19
+ gem.add_dependency 'activerecord'
20
+ gem.add_dependency 'activesupport'
21
+ gem.add_dependency "sinatra-activerecord"
22
+ gem.add_dependency "hooks"
23
+ gem.add_development_dependency 'debugger'
24
+ gem.add_development_dependency 'rspec'
25
+ gem.add_development_dependency "database_cleaner"
26
+ end
data/lib/horde.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "active_record"
2
+ require "hooks"
3
+ require "horde/version"
4
+ require "horde/core_ext/string"
5
+ require "horde/setting"
6
+ require "horde/actions/base"
7
+ require "horde/actions/comment"
8
+ require "horde/actions/favorite"
9
+ require "horde/actions/follow"
10
+ require "horde/actions/rate"
11
+ require "horde/base"
12
+ require "horde/actor"
13
+ require "horde/actions"
14
+
15
+ module Horde
16
+ end
@@ -0,0 +1,14 @@
1
+ module Horde
2
+ module Actions
3
+ module All
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ include ::Horde::Actions::Comment
7
+ include ::Horde::Actions::Favorite
8
+ include ::Horde::Actions::Follow
9
+ include ::Horde::Actions::Rate
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,11 @@
1
+ module Horde
2
+ module Actions
3
+ class Base < ActiveRecord::Base
4
+ self.abstract_class = true
5
+
6
+ belongs_to :target, :polymorphic => true
7
+
8
+ validates_presence_of :actor_id, :target_id, :target_type
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,96 @@
1
+ module Horde
2
+ class Comment < Actions::Base
3
+ self.table_name = 'horde_comments'
4
+
5
+ validates_presence_of :comment
6
+ end
7
+
8
+ module Actions
9
+ module Comment
10
+ extend ActiveSupport::Concern
11
+ included do
12
+ include CommentMethods::TargetMethods
13
+ end
14
+ end
15
+
16
+ module CommentMethods
17
+ # methods for user, usually User class in your app.
18
+ module ActorMethods
19
+ extend ActiveSupport::Concern
20
+ included do
21
+ has_many :created_comments,
22
+ :class_name => "Horde::Comment",
23
+ :foreign_key => :actor_id
24
+ end
25
+
26
+ # user comment something.
27
+ def comment(target, options = {})
28
+ params = {:actor_id => self.id,
29
+ :target_id => target.id,
30
+ :target_type => target.class.name
31
+ }.merge(options)
32
+ comment = ::Horde::Comment.create(params)
33
+ target.run_hook(:after_comment, comment)
34
+
35
+ comment
36
+ end
37
+ end
38
+
39
+ # methods for something to be commented, like article, photo, etc.
40
+ # if your model is Article. Then you'll get following methods
41
+ #
42
+ # article.comments # --> [comment]
43
+ # article.commenters # --> [user]
44
+ #
45
+ # comment.commenter # --> user
46
+ # comment.commented_article # --> article
47
+ #
48
+ # user.commented_articles # --> [article]
49
+ module TargetMethods
50
+ extend ActiveSupport::Concern
51
+ included do
52
+ has_many :comments,
53
+ :class_name => "Horde::Comment",
54
+ :as => :target,
55
+ :order => "created_at DESC"
56
+
57
+ has_many :commenters,
58
+ :through => :comments
59
+
60
+ create_comment_associations
61
+
62
+ include Hooks
63
+ define_hook :after_comment
64
+ end
65
+
66
+ module ClassMethods
67
+ def create_comment_associations
68
+ target_class_name = self.name # like "Article", "Photo"
69
+ assn_name = "commented_#{target_class_name.tableize}" # "commented_articles"
70
+
71
+ # define belongs_to here because Setting.actor_clas_name has not been set
72
+ ::Horde::Comment.belongs_to :commenter,
73
+ :foreign_key => :actor_id,
74
+ :class_name => Horde::Setting.actor_class_name
75
+
76
+ # comment.commented_article, this is created for
77
+ # user.commented_articles to work.
78
+ ::Horde::Comment.belongs_to assn_name.singularize.to_sym,
79
+ :foreign_key => :target_id,
80
+ :class_name => target_class_name
81
+
82
+ Horde::Setting.actor_class_name.constantize.instance_eval do
83
+ include ActorMethods
84
+
85
+ # user.commented_articles
86
+ has_many assn_name,
87
+ :through => :created_comments,
88
+ :source => assn_name.singularize,
89
+ :conditions => {:"horde_comments.target_type" => target_class_name}
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,93 @@
1
+ module Horde
2
+ class Favorite < Actions::Base
3
+ self.table_name = 'horde_favorites'
4
+ end
5
+
6
+ module Actions
7
+ module Favorite
8
+ extend ActiveSupport::Concern
9
+ included do
10
+ include FavoriteMethods::TargetMethods
11
+ end
12
+ end
13
+
14
+ module FavoriteMethods
15
+ # methods for user, usually User class in your app.
16
+ module ActorMethods
17
+ extend ActiveSupport::Concern
18
+ included do
19
+ has_many :created_favorites,
20
+ :class_name => "Horde::Favorite",
21
+ :foreign_key => :actor_id
22
+ end
23
+
24
+ # user favorite something.
25
+ def favorite(target, options = {})
26
+ params = {:actor_id => self.id,
27
+ :target_id => target.id,
28
+ :target_type => target.class.name
29
+ }.merge(options)
30
+ fav = ::Horde::Favorite.create(params)
31
+ target.run_hook(:after_favorite, fav)
32
+
33
+ fav
34
+ end
35
+ end
36
+
37
+ # methods for something to be favorited, like article, photo, etc.
38
+ # if your model is Article. Then you'll get following methods
39
+ #
40
+ # article.favorites # --> [favorite]
41
+ # article.favoriters # --> [user]
42
+ #
43
+ # favorite.favoriter # --> user
44
+ # favorite.favorited_article # --> article
45
+ #
46
+ # user.favorited_articles # --> [article]
47
+ module TargetMethods
48
+ extend ActiveSupport::Concern
49
+ included do
50
+ has_many :favorites,
51
+ :class_name => "Horde::Favorite",
52
+ :as => :target
53
+
54
+ has_many :favoriters,
55
+ :through => :favorites
56
+
57
+ create_favorite_associations
58
+
59
+ include Hooks
60
+ define_hook :after_favorite
61
+ end
62
+
63
+ module ClassMethods
64
+ def create_favorite_associations
65
+ target_class_name = self.name # like "Article", "Photo"
66
+ assn_name = "favorited_#{target_class_name.tableize}" # "favorited_articles"
67
+
68
+ # define belongs_to here because Setting.actor_clas_name has not been set
69
+ ::Horde::Favorite.belongs_to :favoriter,
70
+ :foreign_key => :actor_id,
71
+ :class_name => Horde::Setting.actor_class_name
72
+
73
+ # favorite.favorited_article, this is created for
74
+ # user.favorited_articles to work.
75
+ ::Horde::Favorite.belongs_to assn_name.singularize.to_sym,
76
+ :foreign_key => :target_id,
77
+ :class_name => target_class_name
78
+
79
+ Horde::Setting.actor_class_name.constantize.instance_eval do
80
+ include ActorMethods
81
+
82
+ # user.favorited_articles
83
+ has_many assn_name,
84
+ :through => :created_favorites,
85
+ :source => assn_name.singularize,
86
+ :conditions => {:"horde_favorites.target_type" => target_class_name}
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,93 @@
1
+ module Horde
2
+ class Follow < Actions::Base
3
+ self.table_name = 'horde_follows'
4
+ end
5
+
6
+ module Actions
7
+ module Follow
8
+ extend ActiveSupport::Concern
9
+ included do
10
+ include FollowMethods::TargetMethods
11
+ end
12
+ end
13
+
14
+ module FollowMethods
15
+ # methods for user, usually User class in your app.
16
+ module ActorMethods
17
+ extend ActiveSupport::Concern
18
+ included do
19
+ has_many :created_follows,
20
+ :class_name => "Horde::Follow",
21
+ :foreign_key => :actor_id
22
+ end
23
+
24
+ # user follow something.
25
+ def follow(target, options = {})
26
+ params = {:actor_id => self.id,
27
+ :target_id => target.id,
28
+ :target_type => target.class.name
29
+ }.merge(options)
30
+ follow = ::Horde::Follow.create(params)
31
+ target.run_hook(:after_follow, follow)
32
+
33
+ follow
34
+ end
35
+ end
36
+
37
+ # methods for something to be followed, like article, photo, etc.
38
+ # if your model is Article. Then you'll get following methods
39
+ #
40
+ # article.follows # --> [follow]
41
+ # article.followers # --> [user]
42
+ #
43
+ # follow.follower # --> user
44
+ # follow.followed_article # --> article
45
+ #
46
+ # user.followed_articles # --> [article]
47
+ module TargetMethods
48
+ extend ActiveSupport::Concern
49
+ included do
50
+ has_many :follows,
51
+ :class_name => "Horde::Follow",
52
+ :as => :target
53
+
54
+ has_many :followers,
55
+ :through => :follows
56
+
57
+ create_follow_associations
58
+
59
+ include Hooks
60
+ define_hook :after_follow
61
+ end
62
+
63
+ module ClassMethods
64
+ def create_follow_associations
65
+ target_class_name = self.name # like "Article", "Photo"
66
+ assn_name = "followed_#{target_class_name.tableize}" # "followed_articles"
67
+
68
+ # define belongs_to here because Setting.actor_clas_name has not been set
69
+ ::Horde::Follow.belongs_to :follower,
70
+ :foreign_key => :actor_id,
71
+ :class_name => Horde::Setting.actor_class_name
72
+
73
+ # follow.followed_article, this is created for
74
+ # user.followed_articles to work.
75
+ ::Horde::Follow.belongs_to assn_name.singularize.to_sym,
76
+ :foreign_key => :target_id,
77
+ :class_name => target_class_name
78
+
79
+ Horde::Setting.actor_class_name.constantize.instance_eval do
80
+ include ActorMethods
81
+
82
+ # user.followed_articles
83
+ has_many assn_name,
84
+ :through => :created_follows,
85
+ :source => assn_name.singularize,
86
+ :conditions => {:"horde_follows.target_type" => target_class_name}
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,95 @@
1
+ module Horde
2
+ class Rate < Actions::Base
3
+ self.table_name = 'horde_rates'
4
+
5
+ validates_presence_of :score
6
+ end
7
+
8
+ module Actions
9
+ module Rate
10
+ extend ActiveSupport::Concern
11
+ included do
12
+ include RateMethods::TargetMethods
13
+ end
14
+ end
15
+
16
+ module RateMethods
17
+ # methods for user, usually User class in your app.
18
+ module ActorMethods
19
+ extend ActiveSupport::Concern
20
+ included do
21
+ has_many :created_rates,
22
+ :class_name => "Horde::Rate",
23
+ :foreign_key => :actor_id
24
+ end
25
+
26
+ # user rate something.
27
+ def rate(target, options = {})
28
+ params = {:actor_id => self.id,
29
+ :target_id => target.id,
30
+ :target_type => target.class.name
31
+ }.merge(options)
32
+ rate = ::Horde::Rate.create(params)
33
+ target.run_hook(:after_rate, rate)
34
+
35
+ rate
36
+ end
37
+ end
38
+
39
+ # methods for something to be rated, like article, photo, etc.
40
+ # if your model is Article. Then you'll get following methods
41
+ #
42
+ # article.rates # --> [rate]
43
+ # article.raters # --> [user]
44
+ #
45
+ # rate.rater # --> user
46
+ # rate.rated_article # --> article
47
+ #
48
+ # user.rated_articles # --> [article]
49
+ module TargetMethods
50
+ extend ActiveSupport::Concern
51
+ included do
52
+ has_many :rates,
53
+ :class_name => "Horde::Rate",
54
+ :as => :target
55
+
56
+ has_many :raters,
57
+ :through => :rates
58
+
59
+ create_rate_associations
60
+
61
+ include Hooks
62
+ define_hook :after_rate
63
+ end
64
+
65
+ module ClassMethods
66
+ def create_rate_associations
67
+ target_class_name = self.name # like "Article", "Photo"
68
+ assn_name = "rated_#{target_class_name.tableize}" # "rated_articles"
69
+
70
+ # define belongs_to here because Setting.actor_clas_name has not been set
71
+ ::Horde::Rate.belongs_to :rater,
72
+ :foreign_key => :actor_id,
73
+ :class_name => Horde::Setting.actor_class_name
74
+
75
+ # rate.rated_article, this is created for
76
+ # user.rated_articles to work.
77
+ ::Horde::Rate.belongs_to assn_name.singularize.to_sym,
78
+ :foreign_key => :target_id,
79
+ :class_name => target_class_name
80
+
81
+ Horde::Setting.actor_class_name.constantize.instance_eval do
82
+ include ActorMethods
83
+
84
+ # user.rated_articles
85
+ has_many assn_name,
86
+ :through => :created_rates,
87
+ :source => assn_name.singularize,
88
+ :conditions => {:"horde_rates.target_type" => target_class_name}
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,12 @@
1
+ module Horde
2
+ module Actor
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ # set it so it can be used in defining associations later
6
+ if Horde::Setting.actor_class_name.nil?
7
+ Horde::Setting.actor_class_name = self.name
8
+ end
9
+ end
10
+
11
+ end
12
+ end
data/lib/horde/base.rb ADDED
File without changes
@@ -0,0 +1,13 @@
1
+ class String
2
+ # actorize("comment") # --> commenter
3
+ # actorize("vote") # --> voter
4
+ def actorize
5
+ self =~ /e$/ ? self + "r" : self + "er"
6
+ end
7
+
8
+ # past_tense("comment") # --> commented
9
+ # past_tense("vote") # --> voted
10
+ def past_tense
11
+ self =~ /e$/ ? self + "d" : self + "ed"
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ module Horde
2
+ class Setting
3
+ class << self
4
+ attr_accessor :actor_class_name
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Horde
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "commenting" do
4
+ before(:each) do
5
+ @user = User.create(:login => 'john', :first_name => 'John', :last_name => 'Doe')
6
+ @user2 = User.create(:login => 'jane', :first_name => 'Jane', :last_name => 'Doe')
7
+ @article = Article.create(:title => 'article 1', :author_id => @user2.id)
8
+ @photo = Photo.create(:name => 'photo 1', :author_id => @user2.id)
9
+ @user.comment(@article, :comment => "great article")
10
+ end
11
+
12
+ it "should work for actor" do
13
+ comment = Horde::Comment.first
14
+ comment.should_not be_nil
15
+
16
+ comment.target.should == @article
17
+ @user.created_comments.should include comment
18
+ end
19
+
20
+ it "should find comment by class" do
21
+ comment = Horde::Comment.first
22
+ comment.commented_article.should == @article
23
+ @user.commented_articles.should == [@article]
24
+ end
25
+
26
+ it "should comment photo" do
27
+ @user.comment(@photo, :comment => 'nic pic')
28
+ @user.commented_photos.should == [@photo]
29
+ end
30
+
31
+ it "should work for target" do
32
+ @article.comments.should_not be_empty
33
+ @article.commenters.should include @user
34
+ end
35
+
36
+ it "should run callback" do
37
+ article2 = double("Article", :id => 2, :title => 'article 2', :author_id => @user2.id)
38
+ article2.should_receive(:run_hook)
39
+ @user.comment(article2)
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "favoriting" do
4
+ before(:each) do
5
+ @user = User.create(:login => 'john', :first_name => 'John', :last_name => 'Doe')
6
+ @user2 = User.create(:login => 'jane', :first_name => 'Jane', :last_name => 'Doe')
7
+ @article = Article.create(:title => 'article 1', :author_id => @user2.id)
8
+ @photo = Photo.create(:name => 'photo 1', :author_id => @user2.id)
9
+ @user.favorite(@article)
10
+ end
11
+
12
+ it "should work for actor" do
13
+ fav = Horde::Favorite.first
14
+ fav.should_not be_nil
15
+
16
+ fav.target.should == @article
17
+ @user.created_favorites.should include fav
18
+ end
19
+
20
+ it "should find favorite by class" do
21
+ fav = Horde::Favorite.first
22
+ fav.favorited_article.should == @article
23
+ @user.favorited_articles.should == [@article]
24
+ end
25
+
26
+ it "should favorite photo" do
27
+ @user.favorite(@photo)
28
+ @user.favorited_photos.should == [@photo]
29
+ end
30
+
31
+ it "should work for target" do
32
+ @article.favorites.should_not be_empty
33
+ @article.favoriters.should include @user
34
+ end
35
+
36
+ it "should run callback" do
37
+ article2 = double("Article", :id => 2, :title => 'article 2', :author_id => @user2.id)
38
+ article2.should_receive(:run_hook)
39
+ @user.favorite(article2)
40
+ end
41
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe "following" do
4
+ before(:each) do
5
+ @user = User.create(:login => 'john', :first_name => 'John', :last_name => 'Doe')
6
+ @user2 = User.create(:login => 'jane', :first_name => 'Jane', :last_name => 'Doe')
7
+ @article = Article.create(:title => 'article 1', :author_id => @user2.id)
8
+ @photo = Photo.create(:name => 'photo 1', :author_id => @user2.id)
9
+ @user.follow(@article)
10
+ end
11
+
12
+ it "should work for actor" do
13
+ follow = Horde::Follow.first
14
+ follow.should_not be_nil
15
+
16
+ follow.target.should == @article
17
+ @user.created_follows.should include follow
18
+ end
19
+
20
+ it "should find follow by class" do
21
+ follow = Horde::Follow.first
22
+ follow.followed_article.should == @article
23
+ @user.followed_articles.should == [@article]
24
+ end
25
+
26
+ it "should follow photo" do
27
+ @user.follow(@photo)
28
+ @user.followed_photos.should == [@photo]
29
+ end
30
+
31
+ it "should work for target" do
32
+ @article.follows.should_not be_empty
33
+ @article.followers.should include @user
34
+ end
35
+
36
+ it "should run callback" do
37
+ article2 = double("Article", :id => 2, :title => 'article 2', :author_id => @user2.id)
38
+ article2.should_receive(:run_hook)
39
+ @user.follow(article2)
40
+ end
41
+
42
+ it "should follow user" do
43
+ follow = @user.follow(@user2)
44
+
45
+ follow.target.should == @user2
46
+ follow.followed_user.should == @user2
47
+ follow.follower.should == @user
48
+
49
+ @user.created_follows.should include follow
50
+ @user.followed_users.should == [@user2]
51
+
52
+ @user2.follows.should == [follow]
53
+ @user2.followers.should == [@user]
54
+ end
55
+ end
data/spec/rate_spec.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "rating" do
4
+ before(:each) do
5
+ @user = User.create(:login => 'john', :first_name => 'John', :last_name => 'Doe')
6
+ @user2 = User.create(:login => 'jane', :first_name => 'Jane', :last_name => 'Doe')
7
+ @article = Article.create(:title => 'article 1', :author_id => @user2.id)
8
+ @photo = Photo.create(:name => 'photo 1', :author_id => @user2.id)
9
+ @user.rate(@article, :score => 5)
10
+ end
11
+
12
+ it "should work for actor" do
13
+ rate = Horde::Rate.first
14
+ rate.should_not be_nil
15
+
16
+ rate.target.should == @article
17
+ @user.created_rates.should include rate
18
+ end
19
+
20
+ it "should find rate by class" do
21
+ rate = Horde::Rate.first
22
+ rate.rated_article.should == @article
23
+ @user.rated_articles.should == [@article]
24
+ end
25
+
26
+ it "should rate photo" do
27
+ @user.rate(@photo, :score => 5)
28
+ @user.rated_photos.should == [@photo]
29
+ end
30
+
31
+ it "should work for target" do
32
+ @article.rates.should_not be_empty
33
+ @article.raters.should include @user
34
+ end
35
+
36
+ it "should run callback" do
37
+ article2 = double("Article", :id => 2, :title => 'article 2', :author_id => @user2.id)
38
+ article2.should_receive(:run_hook)
39
+ @user.rate(article2)
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Setting" do
4
+ before(:each) do
5
+ end
6
+
7
+ it "should save actor_class_name to setting" do
8
+ Horde::Setting.actor_class_name.should == 'User'
9
+ end
10
+ end
11
+
@@ -0,0 +1,40 @@
1
+ require 'debugger'
2
+ require 'database_cleaner'
3
+ require 'horde'
4
+
5
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
6
+
7
+ # This file was generated by the `rspec --init` command. Conventionally, all
8
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
9
+ # Require this file using `require "spec_helper"` to ensure that it is only
10
+ # loaded once.
11
+ #
12
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
13
+ RSpec.configure do |config|
14
+ config.treat_symbols_as_metadata_keys_with_true_values = true
15
+ config.run_all_when_everything_filtered = true
16
+ config.filter_run :focus
17
+
18
+ # Run specs in random order to surface order dependencies. If you find an
19
+ # order dependency and want to debug it, you can fix the order by providing
20
+ # the seed, which is printed after each run.
21
+ # --seed 1234
22
+ config.order = 'random'
23
+
24
+ # --- database cleaner config
25
+ config.before(:suite) do
26
+ ActiveRecord::Base.logger = nil
27
+ DatabaseCleaner.strategy = :truncation #:transaction doesn't clean
28
+ DatabaseCleaner.clean_with(:truncation)
29
+ end
30
+
31
+ config.before(:each) do
32
+ DatabaseCleaner.start
33
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
34
+ end
35
+
36
+ config.after(:each) do
37
+ ActiveRecord::Base.logger = nil
38
+ DatabaseCleaner.clean
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'actorize' do
4
+ it "should work on follow" do
5
+ "follow".actorize.should == "follower"
6
+ end
7
+
8
+ it "should work on favorite" do
9
+ "favorite".actorize.should == "favoriter"
10
+ end
11
+
12
+ it "should work on rate" do
13
+ "rate".actorize.should == "rater"
14
+ end
15
+ end
16
+
17
+ describe 'past_tense' do
18
+ it "should work on follow" do
19
+ "follow".past_tense.should == "followed"
20
+ end
21
+
22
+ it "should work on favorite" do
23
+ "favorite".past_tense.should == "favorited"
24
+ end
25
+
26
+ it "should work on rate" do
27
+ "rate".past_tense.should == "rated"
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ test:
2
+ adapter: mysql2
3
+ encoding: utf8
4
+ reconnect: false
5
+ database: horde_test
6
+ pool: 1
7
+ username: root
8
+ password:
9
+ socket: /opt/local/var/run/mysql5/mysqld.sock
@@ -0,0 +1,6 @@
1
+ require 'logger'
2
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
3
+
4
+ db_yml = File.expand_path('../database.yml', __FILE__)
5
+ db_config = YAML.load_file(db_yml)['test']
6
+ ActiveRecord::Base.establish_connection(db_config)
@@ -0,0 +1,18 @@
1
+ class User < ActiveRecord::Base
2
+ include Horde::Actor
3
+ include Horde::Actions::Follow
4
+ end
5
+
6
+ class Article < ActiveRecord::Base
7
+ include Horde::Actions::All
8
+
9
+ after_favorite :email_author
10
+
11
+ def email_author(fav)
12
+ "#{fav.favoriter.login} favorited article #{self.title}"
13
+ end
14
+ end
15
+
16
+ class Photo < ActiveRecord::Base
17
+ include Horde::Actions::All
18
+ end
metadata ADDED
@@ -0,0 +1,220 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: horde-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dorren Chen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mysql2
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
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: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activerecord
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: activesupport
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
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: sinatra-activerecord
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
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: hooks
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: debugger
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
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
+ - !ruby/object:Gem::Dependency
111
+ name: rspec
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: database_cleaner
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ description: A ruby gem providing social networking features for rails app.
143
+ email:
144
+ - dorrenchen@gmail.com
145
+ executables: []
146
+ extensions: []
147
+ extra_rdoc_files: []
148
+ files:
149
+ - .gitignore
150
+ - .rspec
151
+ - Gemfile
152
+ - LICENSE
153
+ - README.md
154
+ - Rakefile
155
+ - db/migrate/20120714150229_horde_setup.rb
156
+ - db/migrate/20120714184427_test_models.rb
157
+ - horde.gemspec
158
+ - lib/horde.rb
159
+ - lib/horde/actions.rb
160
+ - lib/horde/actions/base.rb
161
+ - lib/horde/actions/comment.rb
162
+ - lib/horde/actions/favorite.rb
163
+ - lib/horde/actions/follow.rb
164
+ - lib/horde/actions/rate.rb
165
+ - lib/horde/actor.rb
166
+ - lib/horde/base.rb
167
+ - lib/horde/core_ext/string.rb
168
+ - lib/horde/setting.rb
169
+ - lib/horde/version.rb
170
+ - spec/comment_spec.rb
171
+ - spec/favorite_spec.rb
172
+ - spec/follow_spec.rb
173
+ - spec/rate_spec.rb
174
+ - spec/setting_spec.rb
175
+ - spec/spec_helper.rb
176
+ - spec/string_ext_spec.rb
177
+ - spec/support/database.yml
178
+ - spec/support/db_config.rb
179
+ - spec/support/test_models.rb
180
+ homepage: ''
181
+ licenses: []
182
+ post_install_message:
183
+ rdoc_options: []
184
+ require_paths:
185
+ - lib
186
+ required_ruby_version: !ruby/object:Gem::Requirement
187
+ none: false
188
+ requirements:
189
+ - - ! '>='
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ segments:
193
+ - 0
194
+ hash: 4029953517073986462
195
+ required_rubygems_version: !ruby/object:Gem::Requirement
196
+ none: false
197
+ requirements:
198
+ - - ! '>='
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ segments:
202
+ - 0
203
+ hash: 4029953517073986462
204
+ requirements: []
205
+ rubyforge_project:
206
+ rubygems_version: 1.8.24
207
+ signing_key:
208
+ specification_version: 3
209
+ summary: A ruby gem providing social networking features for rails app.
210
+ test_files:
211
+ - spec/comment_spec.rb
212
+ - spec/favorite_spec.rb
213
+ - spec/follow_spec.rb
214
+ - spec/rate_spec.rb
215
+ - spec/setting_spec.rb
216
+ - spec/spec_helper.rb
217
+ - spec/string_ext_spec.rb
218
+ - spec/support/database.yml
219
+ - spec/support/db_config.rb
220
+ - spec/support/test_models.rb