diff --git a/MIT-LICENSE b/MIT-LICENSE index 23bb544..1ee5344 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -19,7 +19,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -The major design pattern of this plugin was abstracted from Peter Jackson's VoteFu, which is subject to the same license. +The major design pattern of this plugin was abstracted from Peter Jackson's VoteFu, which is subject to the same license. Here is the original copyright notice for VoteFu: Copyright (c) 2008 Peter Jackson (peteonrails.com) diff --git a/README.rdoc b/README.rdoc index d9d8b2c..4b7703a 100644 --- a/README.rdoc +++ b/README.rdoc @@ -28,7 +28,7 @@ Make your model(s) that you want to allow to be followed acts_as_followable, jus acts_as_followable ... end - + class Book < ActiveRecord::Base ... acts_as_followable @@ -64,7 +64,7 @@ To get follow records that have not been blocked use the following user.all_follows # returns an array of Follow records To get all of the records that an object is following that have not been blocked use the following - user.all_following + user.all_following # Returns an array of every followed object for the user, this can be a collection of different object types, eg: User, Book To get all Follow records by a certain type use the following @@ -82,18 +82,18 @@ There is also a method_missing to accomplish the exact same thing a following_by To get all the followers of a model that acts_as_followable book.followers # Returns an array of all the followers for that book, a collection of different object types (eg. type User or type Book) - + To get just the number of follows use book.followers_count - + To see is a model that acts_as_followable is followed by a model that acts_as_follower use the following book.followed_by?(user) - + # Returns true if the current instance is followed by the passed record # Returns false if the current instance is blocked by the passed record or no follow is found To block a follower call the following - book.block(user) + book.block(user) # Blocks the user from appearing in the followers list, and blocks the book from appearing in the user.all_follows or user.all_following lists To unblock is just as simple @@ -105,7 +105,7 @@ To get all blocked records If you only need the number of blocks use the count method provided book.blocked_followers_count -Unblocking deletes all records of that follow, instead of just the :blocked attribute => false the follow is deleted. So, a user would need to try and follow the book again. +Unblocking deletes all records of that follow, instead of just the :blocked attribute => false the follow is deleted. So, a user would need to try and follow the book again. I would like to hear thoughts on this, I may change this to make the follow as :blocked => false instead of deleting the record. --- @@ -114,12 +114,12 @@ I would like to hear thoughts on this, I may change this to make the follow as : The Follow model has a set of named_scope's. In case you want to interface directly with the Follow model you can use them. Follow.unblocked # returns all "unblocked" follow records - + Follow.blocked # returns all "blocked" follow records - + Follow.descending # returns all records in a descending order based on created_at datetime -This method pulls all records created after a certain date. The default is 2 weeks but it takes an optional parameter. +This method pulls all records created after a certain date. The default is 2 weeks but it takes an optional parameter. Follow.recent Follow.recent(4.weeks.ago) @@ -145,7 +145,7 @@ If you have updates or patches or want to contribute I would love to see what yo == Note on Patches/Pull Requests - + * Fork the project. * Make your feature addition or bug fix. * Add tests for it. This is important so I don't break it in a future version unintentionally (acts_as_follower uses Shoulda and Factory Girl) diff --git a/generators/acts_as_follower/USAGE b/generators/acts_as_follower/USAGE index 73d9b8c..06202c0 100644 --- a/generators/acts_as_follower/USAGE +++ b/generators/acts_as_follower/USAGE @@ -1,5 +1,5 @@ Description: run ./script/generate acts_as_follower - + no need to specify a name after acts_as_follower as you can not change the model name from Follow the acts_as_follower_migration file will be created in db/migrate \ No newline at end of file diff --git a/generators/acts_as_follower/acts_as_follower_generator.rb b/generators/acts_as_follower/acts_as_follower_generator.rb index ecd6476..61137c1 100644 --- a/generators/acts_as_follower/acts_as_follower_generator.rb +++ b/generators/acts_as_follower/acts_as_follower_generator.rb @@ -3,11 +3,11 @@ class ActsAsFollowerGenerator < Rails::Generator::Base record do |m| m.directory "app/models" m.template "model.rb", "app/models/follow.rb" - + m.migration_template 'migration.rb', 'db/migrate' end end - + def file_name "acts_as_follower_migration" end diff --git a/generators/acts_as_follower/templates/migration.rb b/generators/acts_as_follower/templates/migration.rb index 9a364b8..d6a60c0 100644 --- a/generators/acts_as_follower/templates/migration.rb +++ b/generators/acts_as_follower/templates/migration.rb @@ -10,7 +10,7 @@ class ActsAsFollowerMigration < ActiveRecord::Migration add_index :follows, ["follower_id", "follower_type"], :name => "fk_follows" add_index :follows, ["followable_id", "followable_type"], :name => "fk_followables" end - + def self.down drop_table :follows end diff --git a/generators/acts_as_follower/templates/model.rb b/generators/acts_as_follower/templates/model.rb index ece7008..f3e5ba9 100644 --- a/generators/acts_as_follower/templates/model.rb +++ b/generators/acts_as_follower/templates/model.rb @@ -1,19 +1,19 @@ class Follow < ActiveRecord::Base - + named_scope :for_follower, lambda { |*args| {:conditions => ["follower_id = ? AND follower_type = ?", args.first.id, args.first.type.name]} } named_scope :for_followable, lambda { |*args| {:conditions => ["followable_id = ? AND followable_type = ?", args.first.id, args.first.type.name]} } named_scope :recent, lambda { |*args| {:conditions => ["created_at > ?", (args.first || 2.weeks.ago).to_s(:db)]} } named_scope :descending, :order => "created_at DESC" named_scope :unblocked, :conditions => {:blocked => false} named_scope :blocked, :conditions => {:blocked => true} - + # NOTE: Follows belong to the "followable" interface, and also to followers belongs_to :followable, :polymorphic => true belongs_to :follower, :polymorphic => true - + def block! self.update_attribute(:blocked, true) end - + end diff --git a/lib/acts_as_followable.rb b/lib/acts_as_followable.rb index 561af7b..079f455 100644 --- a/lib/acts_as_followable.rb +++ b/lib/acts_as_followable.rb @@ -1,75 +1,75 @@ -require File.dirname(__FILE__) + '/follower_lib' - -module ActiveRecord #:nodoc: - module Acts #:nodoc: - module Followable - - def self.included(base) - base.extend ClassMethods - base.class_eval do - include FollowerLib - end - end - - module ClassMethods - def acts_as_followable - has_many :followings, :as => :followable, :dependent => :destroy, :class_name => 'Follow' - include ActiveRecord::Acts::Followable::InstanceMethods - end - end - - - module InstanceMethods - - # Returns the number of followers a record has. - def followers_count - self.followings.unblocked.count +require File.dirname(__FILE__) + '/follower_lib' + +module ActiveRecord #:nodoc: + module Acts #:nodoc: + module Followable + + def self.included(base) + base.extend ClassMethods + base.class_eval do + include FollowerLib end - + end + + module ClassMethods + def acts_as_followable + has_many :followings, :as => :followable, :dependent => :destroy, :class_name => 'Follow' + include ActiveRecord::Acts::Followable::InstanceMethods + end + end + + + module InstanceMethods + + # Returns the number of followers a record has. + def followers_count + self.followings.unblocked.count + end + def blocked_followers_count self.followings.blocked.count - end - - # Returns the following records. - def followers - self.followings.unblocked.all(:include => [:follower]).collect{|f| f.follower} end - + + # Returns the following records. + def followers + self.followings.unblocked.all(:include => [:follower]).collect{|f| f.follower} + end + def blocks self.followings.blocked.all(:include => [:follower]).collect{|f| f.follower} - end - + end + # Returns true if the current instance is followed by the passed record - # Returns false if the current instance is blocked by the passed record or no follow is found - def followed_by?(follower) + # Returns false if the current instance is blocked by the passed record or no follow is found + def followed_by?(follower) f = get_follow_for(follower) - (f && !f.blocked?) ? true : false + (f && !f.blocked?) ? true : false end - + def block(follower) get_follow_for(follower) ? block_existing_follow(follower) : block_future_follow(follower) end - + def unblock(follower) get_follow_for(follower).try(:delete) end - + private - + def get_follow_for(follower) Follow.find(:first, :conditions => ["followable_id = ? AND followable_type = ? AND follower_id = ? AND follower_type = ?", self.id, parent_class_name(self), follower.id, parent_class_name(follower)]) - end - + end + def block_future_follow(follower) follows.create(:followable => self, :follower => follower, :blocked => true) end - + def block_existing_follow(follower) get_follow_for(follower).block! end - - end - - end - end + + end + + end + end end diff --git a/lib/acts_as_follower.rb b/lib/acts_as_follower.rb index 96de3e9..eb2f7ea 100644 --- a/lib/acts_as_follower.rb +++ b/lib/acts_as_follower.rb @@ -1,100 +1,94 @@ -require File.dirname(__FILE__) + '/follower_lib' - -module ActiveRecord #:nodoc: - module Acts #:nodoc: - module Follower - - def self.included(base) - base.extend ClassMethods - base.class_eval do - include FollowerLib - end - end - - module ClassMethods - def acts_as_follower - has_many :follows, :as => :follower, :dependent => :destroy - include ActiveRecord::Acts::Follower::InstanceMethods - end - end - - module InstanceMethods - - # Returns true if this instance is following the object passed as an argument. - def following?(followable) - 0 < Follow.unblocked.count(:all, :conditions => [ - "follower_id = ? AND follower_type = ? AND followable_id = ? AND followable_type = ?", - self.id, parent_class_name(self), followable.id, parent_class_name(followable) - ]) - end - - # Returns the number of objects this instance is following. - def follow_count - Follow.unblocked.count(:all, :conditions => ["follower_id = ? AND follower_type = ?", self.id, parent_class_name(self)]) - end - - # Creates a new follow record for this instance to follow the passed object. - # Does not allow duplicate records to be created. - def follow(followable) - follow = get_follow(followable) - unless follow - Follow.create(:followable => followable, :follower => self) - end - end - - # Deletes the follow record if it exists. - def stop_following(followable) - follow = get_follow(followable) - if follow - follow.destroy - end - end - - # Returns the follow records related to this instance by type. - def follows_by_type(followable_type) - Follow.unblocked.find(:all, :include => [:followable], :conditions => ["follower_id = ? AND follower_type = ? AND followable_type = ?", self.id, parent_class_name(self), followable_type]) - end - - # Returns the follow records related to this instance with the followable included. - def all_follows - self.follows.unblocked.all(:include => :followable) - end - - # Returns the actual records which this instance is following. - def all_following - all_follows.collect{ |f| f.followable } - end - - # Returns the actual records of a particular type which this record is following. - def following_by_type(followable_type) - follows_by_type(followable_type).collect{ |f| f.followable } - end - - def following_by_type_count(followable_type) - Follow.unblocked.count(:all, :conditions => ["follower_id = ? AND follower_type = ? AND followable_type = ?", self.id, parent_class_name(self), followable_type]) - end - - # Allows magic names on following_by_type - # e.g. following_users == following_by_type('User') - def method_missing(m, *args) - if m.to_s[/following_(.+)_count/] - following_by_type_count($1.singularize.classify) - elsif m.to_s[/following_(.+)/] - following_by_type($1.singularize.classify) - else - super - end - end - - private - - # Returns a follow record for the current instance and followable object. - def get_follow(followable) - Follow.unblocked.find(:first, :conditions => ["follower_id = ? AND follower_type = ? AND followable_id = ? AND followable_type = ?", self.id, parent_class_name(self), followable.id, parent_class_name(followable)]) - end - - end - - end - end -end +require File.dirname(__FILE__) + '/follower_lib' + +module ActiveRecord #:nodoc: + module Acts #:nodoc: + module Follower + + def self.included(base) + base.extend ClassMethods + base.class_eval do + include FollowerLib + end + end + + module ClassMethods + def acts_as_follower + has_many :follows, :as => :follower, :dependent => :destroy + include ActiveRecord::Acts::Follower::InstanceMethods + end + end + + module InstanceMethods + + # Returns true if this instance is following the object passed as an argument. + def following?(followable) + 0 < Follow.unblocked.count(:all, :conditions => [ + "follower_id = ? AND follower_type = ? AND followable_id = ? AND followable_type = ?", + self.id, parent_class_name(self), followable.id, parent_class_name(followable) + ]) + end + + # Returns the number of objects this instance is following. + def follow_count + Follow.unblocked.count(:all, :conditions => ["follower_id = ? AND follower_type = ?", self.id, parent_class_name(self)]) + end + + # Creates a new follow record for this instance to follow the passed object. + # Does not allow duplicate records to be created. + def follow(followable) + follow = get_follow(followable) + unless follow + Follow.create(:followable => followable, :follower => self) + end + end + + # Deletes the follow record if it exists. + def stop_following(followable) + follow = get_follow(followable) + if follow + follow.destroy + end + end + + # Returns the follow records related to this instance by type. + def follows_by_type(followable_type) + Follow.unblocked.find(:all, :include => [:followable], :conditions => ["follower_id = ? AND follower_type = ? AND followable_type = ?", self.id, parent_class_name(self), followable_type]) + end + + # Returns the follow records related to this instance with the followable included. + def all_follows + self.follows.unblocked.all(:include => :followable) + end + + # Returns the actual records which this instance is following. + def all_following + all_follows.collect{ |f| f.followable } + end + + # Returns the actual records of a particular type which this record is following. + def following_by_type(followable_type) + follows_by_type(followable_type).collect{ |f| f.followable } + end + + # Allows magic names on following_by_type + # e.g. following_users == following_by_type('User') + def method_missing(m, *args) + if m.to_s[/following_(.+)/] + following_by_type($1.singularize.classify) + else + super + end + end + + private + + # Returns a follow record for the current instance and followable object. + def get_follow(followable) + Follow.unblocked.find(:first, :conditions => ["follower_id = ? AND follower_type = ? AND followable_id = ? AND followable_type = ?", self.id, parent_class_name(self), followable.id, parent_class_name(followable)]) + end + + end + + end + end +end diff --git a/lib/follower_lib.rb b/lib/follower_lib.rb index 7c27383..be52800 100644 --- a/lib/follower_lib.rb +++ b/lib/follower_lib.rb @@ -1,7 +1,7 @@ module FollowerLib - + private - + # Retrieves the parent class name if using STI. def parent_class_name(obj) if obj.class.superclass != ActiveRecord::Base @@ -9,5 +9,5 @@ module FollowerLib end return obj.class.name end - + end diff --git a/test/TESTING b/test/TESTING index 02a21d5..f6c17ed 100644 --- a/test/TESTING +++ b/test/TESTING @@ -1,48 +1,48 @@ -Testing -============== - -Tests are written with Shoulda on top of Test::Unit and Factory Girl is used instead of fixtures. Tests are run using rake. -Test can either be run against a MySQL database or the faster in-memory SQLite3. - - -MySQL -======= - -1. Create a new Rails app. -2. Install acts_as_follower as a plugin. -3. Copy the database config within the plugin: - cp test/database.yml.example test/database.yml -4. Create a database as specified in test/database.yml. -5. Run the tests: - rake test - - -SQLite3 -======= - -1. Create a new Rails app. -2. Install acts_as_follower as a plugin. -3. Copy the database config within the plugin: - cp test/database.yml.example test/database.yml -4. Install the sqlite3 library (if you don't have it already): - sudo gem install sqlite3-ruby -5. Run the tests: - DB=sqlite3 rake test - - -Coverage -======= - -Test coverage can be calculated using Rcov. Make sure you have the rcov gem installed. - -Again in the acts_as_follower directory: - -rake rcov:gen # For mysql - -or: - -rake rcov:gen DB=sqlite3 # For sqlite - -The coverage will now be available in the test/coverage directory. - -rake rcov:clobber will delete the coverage directory. +Testing +============== + +Tests are written with Shoulda on top of Test::Unit and Factory Girl is used instead of fixtures. Tests are run using rake. +Test can either be run against a MySQL database or the faster in-memory SQLite3. + + +MySQL +======= + +1. Create a new Rails app. +2. Install acts_as_follower as a plugin. +3. Copy the database config within the plugin: + cp test/database.yml.example test/database.yml +4. Create a database as specified in test/database.yml. +5. Run the tests: + rake test + + +SQLite3 +======= + +1. Create a new Rails app. +2. Install acts_as_follower as a plugin. +3. Copy the database config within the plugin: + cp test/database.yml.example test/database.yml +4. Install the sqlite3 library (if you don't have it already): + sudo gem install sqlite3-ruby +5. Run the tests: + DB=sqlite3 rake test + + +Coverage +======= + +Test coverage can be calculated using Rcov. Make sure you have the rcov gem installed. + +Again in the acts_as_follower directory: + +rake rcov:gen # For mysql + +or: + +rake rcov:gen DB=sqlite3 # For sqlite + +The coverage will now be available in the test/coverage directory. + +rake rcov:clobber will delete the coverage directory. diff --git a/test/acts_as_followable_test.rb b/test/acts_as_followable_test.rb index efb1459..0dce673 100644 --- a/test/acts_as_followable_test.rb +++ b/test/acts_as_followable_test.rb @@ -1,139 +1,139 @@ -require File.dirname(__FILE__) + '/test_helper' - -class ActsAsFollowableTest < Test::Unit::TestCase - - context "instance methods" do - setup do - @sam = Factory(:sam) - end - - should "be defined" do - assert @sam.respond_to?(:followers_count) - assert @sam.respond_to?(:followers) - assert @sam.respond_to?(:followed_by?) - end - end - - context "acts_as_followable" do - setup do - @sam = Factory(:sam) - @jon = Factory(:jon) - @sam.follow(@jon) - end - - context "followers_count" do - should "return the number of followers" do - assert_equal 0, @sam.followers_count - assert_equal 1, @jon.followers_count - end - should "return the proper number of multiple followers" do - @bob = Factory(:bob) - @sam.follow(@bob) - assert_equal 0, @sam.followers_count - assert_equal 1, @jon.followers_count - assert_equal 1, @bob.followers_count - end - end - - context "followers" do - should "return users" do - assert_equal [], @sam.followers - assert_equal [@sam], @jon.followers - end - should "return users (multiple followers)" do - @bob = Factory(:bob) - @sam.follow(@bob) - assert_equal [], @sam.followers - assert_equal [@sam], @jon.followers - assert_equal [@sam], @bob.followers - end - should "return users (multiple followers, complex)" do - @bob = Factory(:bob) - @sam.follow(@bob) - @jon.follow(@bob) - assert_equal [], @sam.followers - assert_equal [@sam], @jon.followers - assert_equal [@sam, @jon], @bob.followers - end - end - - context "followed_by" do - should "return_follower_status" do - assert_equal true, @jon.followed_by?(@sam) - assert_equal false, @sam.followed_by?(@jon) - end - end - - context "destroying a followable" do - setup do - @jon.destroy - end - - should_change("follow count", :by => -1) { Follow.count } - should_change("@sam.all_following.size", :by => -1) { @sam.all_following.size } +require File.dirname(__FILE__) + '/test_helper' + +class ActsAsFollowableTest < Test::Unit::TestCase + + context "instance methods" do + setup do + @sam = Factory(:sam) end - + + should "be defined" do + assert @sam.respond_to?(:followers_count) + assert @sam.respond_to?(:followers) + assert @sam.respond_to?(:followed_by?) + end + end + + context "acts_as_followable" do + setup do + @sam = Factory(:sam) + @jon = Factory(:jon) + @sam.follow(@jon) + end + + context "followers_count" do + should "return the number of followers" do + assert_equal 0, @sam.followers_count + assert_equal 1, @jon.followers_count + end + should "return the proper number of multiple followers" do + @bob = Factory(:bob) + @sam.follow(@bob) + assert_equal 0, @sam.followers_count + assert_equal 1, @jon.followers_count + assert_equal 1, @bob.followers_count + end + end + + context "followers" do + should "return users" do + assert_equal [], @sam.followers + assert_equal [@sam], @jon.followers + end + should "return users (multiple followers)" do + @bob = Factory(:bob) + @sam.follow(@bob) + assert_equal [], @sam.followers + assert_equal [@sam], @jon.followers + assert_equal [@sam], @bob.followers + end + should "return users (multiple followers, complex)" do + @bob = Factory(:bob) + @sam.follow(@bob) + @jon.follow(@bob) + assert_equal [], @sam.followers + assert_equal [@sam], @jon.followers + assert_equal [@sam, @jon], @bob.followers + end + end + + context "followed_by" do + should "return_follower_status" do + assert_equal true, @jon.followed_by?(@sam) + assert_equal false, @sam.followed_by?(@jon) + end + end + + context "destroying a followable" do + setup do + @jon.destroy + end + + should_change("follow count", :by => -1) { Follow.count } + should_change("@sam.all_following.size", :by => -1) { @sam.all_following.size } + end + context "blocking a follower" do setup do @jon.block(@sam) end - + should "remove him from followers" do assert_equal 0, @jon.followers_count end - + should "add him to the blocked followers" do assert_equal 1, @jon.blocked_followers_count end - + should "not be able to follow again" do assert_equal 0, @jon.followers_count end - + should "not be present when listing followers" do assert_equal [], @jon.followers end - + should "be in the list of blocks" do assert_equal [@sam], @jon.blocks end end - + context "unblocking a blocked follow" do setup do @jon.block(@sam) @jon.unblock(@sam) end - + should "not include the unblocked user in the list of followers" do assert_equal [], @jon.followers end - + should "remove him from the blocked followers" do assert_equal 0, @jon.blocked_followers_count assert_equal [], @jon.blocks end end - + context "unblock a non-existent follow" do setup do @sam.stop_following(@jon) @jon.unblock(@sam) end - + should "not be in the list of followers" do assert_equal [], @jon.followers end - + should "not be in the blockked followers count" do assert_equal 0, @jon.blocked_followers_count end - + should "not be in the blocks list" do assert_equal [], @jon.blocks end end - - end - -end + + end + +end diff --git a/test/acts_as_follower_test.rb b/test/acts_as_follower_test.rb index 6d6a009..eb2dae5 100644 --- a/test/acts_as_follower_test.rb +++ b/test/acts_as_follower_test.rb @@ -1,168 +1,150 @@ -require File.dirname(__FILE__) + '/test_helper' - -class ActsAsFollowerTest < Test::Unit::TestCase - - context "instance methods" do - setup do - @sam = Factory(:sam) - end - - should "be defined" do - assert @sam.respond_to?(:following?) - assert @sam.respond_to?(:follow_count) - assert @sam.respond_to?(:follow) - assert @sam.respond_to?(:stop_following) - assert @sam.respond_to?(:follows_by_type) - assert @sam.respond_to?(:all_follows) - end - end - - context "acts_as_follower" do - setup do - @sam = Factory(:sam) - @jon = Factory(:jon) - @oasis = Factory(:oasis) - @sam.follow(@jon) - @sam.follow(@oasis) - end - - context "following" do - should "return following_status" do - assert_equal true, @sam.following?(@jon) - assert_equal false, @jon.following?(@sam) - end - - should "return follow_count" do - assert_equal 2, @sam.follow_count - assert_equal 0, @jon.follow_count - end - end - - context "follow" do - setup do - @jon.follow(@sam) - end - - should_change("Follow count", :by => 1) { Follow.count } - should_change("@jon.follow_count", :by => 1) { @jon.follow_count } - - should "set the follower" do - assert_equal @jon, Follow.last.follower - end - - should "set the followable" do - assert_equal @sam, Follow.last.followable - end - end - - context "stop_following" do - setup do - @sam.stop_following(@jon) - end - - should_change("Follow count", :by => -1) { Follow.count } - should_change("@sam.follow_count", :by => -1) { @sam.follow_count } - end - - context "follows" do - setup do - @band_follow = Follow.find(:first, :conditions => ["follower_id = ? and follower_type = 'User' and followable_id = ? and followable_type = 'Band'", @sam.id, @oasis.id]) - @user_follow = Follow.find(:first, :conditions => ["follower_id = ? and follower_type = 'User' and followable_id = ? and followable_type = 'User'", @sam.id, @jon.id]) - end - - context "follows_by_type" do - should "only return requested follows" do - assert_equal [@band_follow], @sam.follows_by_type('Band') - assert_equal [@user_follow], @sam.follows_by_type('User') - end - end - - context "all_follows" do - should "return all follows" do - assert_equal 2, @sam.all_follows.size - assert @sam.all_follows.include?(@band_follow) - assert @sam.all_follows.include?(@user_follow) - assert_equal [], @jon.all_follows - end - end - end - - context "all_following" do - should "return the actual follow records" do - assert_equal 2, @sam.all_following.size - assert @sam.all_following.include?(@oasis) - assert @sam.all_following.include?(@jon) - assert_equal [], @jon.all_following - end - end - - context "following_by_type" do - should "return only requested records" do - assert_equal [@oasis], @sam.following_by_type('Band') - assert_equal [@jon], @sam.following_by_type('User') - end - end - - context "following_by_type_count" do - should "return the count of the requested type" do - assert_equal 1, @sam.following_by_type_count('Band') - assert_equal 1, @sam.following_by_type_count('User') - assert_equal 0, @jon.following_by_type_count('Band') - @jon.block(@sam) - assert_equal 0, @sam.following_by_type_count('User') - end - end - - context "method_missing" do - should "call following_by_type" do - assert_equal [@oasis], @sam.following_bands - assert_equal [@jon], @sam.following_users - end - - should "call following_by_type_count" do - assert_equal 1, @sam.following_bands_count - assert_equal 1, @sam.following_users_count - assert_equal 0, @jon.following_bands_count - @jon.block(@sam) - assert_equal 0, @sam.following_users_count - end - - should "raise on no method" do - assert_raises (NoMethodError){ @sam.foobar } - end - end - - context "destroying follower" do - setup do - @jon.destroy - end - - should_change("Follow.count", :by => -1) { Follow.count } - should_change("@sam.follow_count", :by => -1) { @sam.follow_count } - end - - context "blocked by followable" do - setup do - @jon.block(@sam) - end - - should "return following_status" do - assert_equal false, @sam.following?(@jon) - end - - should "return follow_count" do - assert_equal 1, @sam.follow_count - end - - should "not return record of the blocked follows" do - assert_equal 1, @sam.all_follows.size - assert !@sam.all_follows.include?(@user_follow) - assert !@sam.all_following.include?(@jon) - assert_equal [], @sam.following_by_type('User') - assert_equal [], @sam.follows_by_type('User') - assert_equal [], @sam.following_users - end - end - end - -end +require File.dirname(__FILE__) + '/test_helper' + +class ActsAsFollowerTest < Test::Unit::TestCase + + context "instance methods" do + setup do + @sam = Factory(:sam) + end + + should "be defined" do + assert @sam.respond_to?(:following?) + assert @sam.respond_to?(:follow_count) + assert @sam.respond_to?(:follow) + assert @sam.respond_to?(:stop_following) + assert @sam.respond_to?(:follows_by_type) + assert @sam.respond_to?(:all_follows) + end + end + + context "acts_as_follower" do + setup do + @sam = Factory(:sam) + @jon = Factory(:jon) + @oasis = Factory(:oasis) + @sam.follow(@jon) + @sam.follow(@oasis) + end + + context "following" do + should "return following_status" do + assert_equal true, @sam.following?(@jon) + assert_equal false, @jon.following?(@sam) + end + + should "return follow_count" do + assert_equal 2, @sam.follow_count + assert_equal 0, @jon.follow_count + end + end + + context "follow" do + setup do + @jon.follow(@sam) + end + + should_change("Follow count", :by => 1) { Follow.count } + should_change("@jon.follow_count", :by => 1) { @jon.follow_count } + + should "set the follower" do + assert_equal @jon, Follow.last.follower + end + + should "set the followable" do + assert_equal @sam, Follow.last.followable + end + end + + context "stop_following" do + setup do + @sam.stop_following(@jon) + end + + should_change("Follow count", :by => -1) { Follow.count } + should_change("@sam.follow_count", :by => -1) { @sam.follow_count } + end + + context "follows" do + setup do + @band_follow = Follow.find(:first, :conditions => ["follower_id = ? and follower_type = 'User' and followable_id = ? and followable_type = 'Band'", @sam.id, @oasis.id]) + @user_follow = Follow.find(:first, :conditions => ["follower_id = ? and follower_type = 'User' and followable_id = ? and followable_type = 'User'", @sam.id, @jon.id]) + end + + context "follows_by_type" do + should "only return requested follows" do + assert_equal [@band_follow], @sam.follows_by_type('Band') + assert_equal [@user_follow], @sam.follows_by_type('User') + end + end + + context "all_follows" do + should "return all follows" do + assert_equal 2, @sam.all_follows.size + assert @sam.all_follows.include?(@band_follow) + assert @sam.all_follows.include?(@user_follow) + assert_equal [], @jon.all_follows + end + end + end + + context "all_following" do + should "return the actual follow records" do + assert_equal 2, @sam.all_following.size + assert @sam.all_following.include?(@oasis) + assert @sam.all_following.include?(@jon) + assert_equal [], @jon.all_following + end + end + + context "following_by_type" do + should "return only requested records" do + assert_equal [@oasis], @sam.following_by_type('Band') + assert_equal [@jon], @sam.following_by_type('User') + end + end + + context "method_missing" do + should "call following_by_type" do + assert_equal [@oasis], @sam.following_bands + assert_equal [@jon], @sam.following_users + end + + should "raise on no method" do + assert_raises (NoMethodError){ @sam.foobar } + end + end + + context "destroying follower" do + setup do + @jon.destroy + end + + should_change("Follow.count", :by => -1) { Follow.count } + should_change("@sam.follow_count", :by => -1) { @sam.follow_count } + end + + context "blocked by followable" do + setup do + @jon.block(@sam) + end + + should "return following_status" do + assert_equal false, @sam.following?(@jon) + end + + should "return follow_count" do + assert_equal 1, @sam.follow_count + end + + should "not return record of the blocked follows" do + assert_equal 1, @sam.all_follows.size + assert !@sam.all_follows.include?(@user_follow) + assert !@sam.all_following.include?(@jon) + assert_equal [], @sam.following_by_type('User') + assert_equal [], @sam.follows_by_type('User') + assert_equal [], @sam.following_users + end + end + end + +end diff --git a/test/database.yml.example b/test/database.yml.example index d4f12f0..c9b7860 100644 --- a/test/database.yml.example +++ b/test/database.yml.example @@ -2,7 +2,7 @@ mysql: adapter: mysql host: localhost username: root - password: + password: database: rails_plugin_test sqlite3: diff --git a/test/factories/bands.rb b/test/factories/bands.rb index 48492c8..fd86c93 100644 --- a/test/factories/bands.rb +++ b/test/factories/bands.rb @@ -1,3 +1,3 @@ -Factory.define :oasis, :class => Band do |b| - b.name 'Oasis' -end +Factory.define :oasis, :class => Band do |b| + b.name 'Oasis' +end diff --git a/test/factories/users.rb b/test/factories/users.rb index 339f37d..3aef0c0 100644 --- a/test/factories/users.rb +++ b/test/factories/users.rb @@ -1,11 +1,11 @@ -Factory.define :jon, :class => User do |u| - u.name 'Jon' -end - -Factory.define :sam, :class => User do |u| - u.name 'Sam' -end - -Factory.define :bob, :class => User do |u| - u.name 'Bob' -end +Factory.define :jon, :class => User do |u| + u.name 'Jon' +end + +Factory.define :sam, :class => User do |u| + u.name 'Sam' +end + +Factory.define :bob, :class => User do |u| + u.name 'Bob' +end diff --git a/test/follow_test.rb b/test/follow_test.rb index 6b63694..73da53c 100644 --- a/test/follow_test.rb +++ b/test/follow_test.rb @@ -1,10 +1,10 @@ -require File.dirname(__FILE__) + '/test_helper' - -class FollowTest < Test::Unit::TestCase - - # Replace with real tests - def test_assert_true_should_be_true - assert true - end - -end +require File.dirname(__FILE__) + '/test_helper' + +class FollowTest < Test::Unit::TestCase + + # Replace with real tests + def test_assert_true_should_be_true + assert true + end + +end diff --git a/test/models/band.rb b/test/models/band.rb index db90d74..7f94535 100644 --- a/test/models/band.rb +++ b/test/models/band.rb @@ -1,4 +1,4 @@ -class Band < ActiveRecord::Base - validates_presence_of :name - acts_as_followable -end +class Band < ActiveRecord::Base + validates_presence_of :name + acts_as_followable +end diff --git a/test/models/user.rb b/test/models/user.rb index 81f35b4..ab286bd 100644 --- a/test/models/user.rb +++ b/test/models/user.rb @@ -1,5 +1,5 @@ -class User < ActiveRecord::Base - validates_presence_of :name - acts_as_follower - acts_as_followable -end +class User < ActiveRecord::Base + validates_presence_of :name + acts_as_follower + acts_as_followable +end diff --git a/test/schema.rb b/test/schema.rb index cca8de6..67cd1d3 100644 --- a/test/schema.rb +++ b/test/schema.rb @@ -1,5 +1,5 @@ ActiveRecord::Schema.define :version => 0 do - + create_table :follows, :force => true do |t| t.integer "followable_id", :null => false t.string "followable_type", :null => false @@ -9,13 +9,13 @@ ActiveRecord::Schema.define :version => 0 do t.datetime "created_at" t.datetime "updated_at" end - + create_table :users, :force => true do |t| t.column :name, :string end - + create_table :bands, :force => true do |t| t.column :name, :string end - + end diff --git a/test/test_helper.rb b/test/test_helper.rb index f13a35e..b442a75 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,18 +1,18 @@ -require 'rubygems' -require 'active_record' -require 'active_record/base' - -require File.dirname(__FILE__) + '/../init.rb' -require File.dirname(__FILE__) + '/models/band' -require File.dirname(__FILE__) + '/models/user' -require File.dirname(__FILE__) + '/../generators/acts_as_follower/templates/model.rb' - -require 'test/unit' -require 'shoulda' -require 'factory_girl' - -ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log') -ActiveRecord::Base.configurations = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) -ActiveRecord::Base.establish_connection(ENV['DB'] || 'mysql') - -load(File.dirname(__FILE__) + '/schema.rb') +require 'rubygems' +require 'active_record' +require 'active_record/base' + +require File.dirname(__FILE__) + '/../init.rb' +require File.dirname(__FILE__) + '/models/band' +require File.dirname(__FILE__) + '/models/user' +require File.dirname(__FILE__) + '/../generators/acts_as_follower/templates/model.rb' + +require 'test/unit' +require 'shoulda' +require 'factory_girl' + +ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log') +ActiveRecord::Base.configurations = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) +ActiveRecord::Base.establish_connection(ENV['DB'] || 'mysql') + +load(File.dirname(__FILE__) + '/schema.rb') -- libgit2 0.21.0