social_feed 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ *.sqlite3
data/INSTALL ADDED
@@ -0,0 +1,22 @@
1
+ Plugin setup
2
+
3
+ * to create the necessary migration run:
4
+
5
+ script/generate social_feed_migration
6
+ rake db:migrate
7
+
8
+ * add the following line to the top of your config/routes.rb:
9
+
10
+ map.from_plugin 'social_feed'
11
+
12
+ * add the following line to the Rails::Initializer block in your environment.rb
13
+
14
+ config.load_paths << RAILS_ROOT + '/app/models/events'
15
+
16
+ * add the following line to your User class
17
+
18
+ include SocialFeed::UserExtension
19
+
20
+ * make sure you have the prototype javascript library loaded in your views, e.g. with the following line in your views/layouts/application.html.erb
21
+
22
+ <%= javascript_include_tag :defaults %>
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,96 @@
1
+ SocialFeed
2
+ ==========
3
+
4
+ This plugin adds a social feed to your rails application. Users can decide what kinds of events they want to see on their social feed and also wether they want to be sent an email when an event occurs. They can also decide wether others will receive a notification on their social feed concerning their own actions.
5
+
6
+ How it works
7
+ ============
8
+
9
+ The plugins adds the following things to your application
10
+ * a FeedEvent model - this represents an event on the social feed - you will subclass the SocialFeed to create your own custom events
11
+ * a SocialFeedsController - this controller has actions for:
12
+ * displaying the social feed for a user (index)
13
+ * destroying a SocialFeed
14
+ * displaying a settings page where users can
15
+ * subscribe to and unsubscribe from events
16
+ * subscirbe to and unsubscribe from receiving emails for events
17
+ * enable/disable the creation of events concerning their own actions in the application
18
+ * a migration that adds 3 fields to your users table to store the event subscriptions
19
+
20
+
21
+ Installation
22
+ ============
23
+
24
+ If you are on rails >= 2.1 (which supports git) you can simply do a
25
+ script/plugin install git://github.com/langalex/social_feed.git
26
+
27
+ If not you need to do this from your rails root:
28
+
29
+ cd vendor/plugins
30
+ git clone git://github.com/langalex/social_feed.git --depth 1
31
+ cd social_feed
32
+ ruby install.rb
33
+ cd ../../..
34
+
35
+ for the rest see the INSTALL file
36
+
37
+ Assumptions
38
+ ===========
39
+
40
+ the socialfeed plugin assumes that:
41
+
42
+ * your users are represented via the User model
43
+ * your users have an email attribute (used by the feed event mailer)
44
+ * the controllers in your application have access to the currently logged in user via the current_user method
45
+
46
+ Basic User Experience
47
+ =====================
48
+
49
+ After the plugin is installed you can direct your users to the /feed_events url which will show them their personal social feed. To customize their events the users should go to /feed_events/settings
50
+
51
+ How to create custom events types
52
+ =================================
53
+
54
+ To create a custom event you should use the built-in feed_event generator:
55
+
56
+ e.g.: script/generate feed_event new_friend
57
+
58
+ This creates a new class NewFriendEvent in the app/models/events directory (the class representing the event) as well as a new_friend_hint.html.erb file in the app/views/feed_events directory (this gets rendered on people's social feed page). First thing you probably want to do is to customize the hint file.
59
+
60
+ Secondly you should also customize the two description lines in the model, which will be used on the setting page. By commenting out either line, you can remove the corresponding line from the setings page.
61
+
62
+ If you want your users to be able to receive emails for your new event, add a method deliver_new_friend(event) to the FeedEventMailer found in app/models/feed_events. You can call the convenience method create_event_message(subject, event) to send your mails. After adding the method a checkbox for this event will automatically appear on the settings page.
63
+
64
+ Creating actual events
65
+ ======================
66
+
67
+ In order for the social feeds of your users to get filled with events you have to create instances of your custom event classes. You have a number of choices here. I would recommend to use the rails observers, so for a NewFriendEvent you would probably create a FriendShipObserver with an after_create hook that creates the event after a new friendship has been created. As soon as you start creating lots of events for a single action (e.g. tell every user that user X and user Y are now friends) I would highly recommend using something asynchronous like the workling plugin and starling.
68
+
69
+ An event requires two attributes, a user and a source. The user is the user who sees the event on her social feed, the source is the object that sort of caused the event, which in this example would be the friendship, e.g.
70
+
71
+ NewFriendEvent.create :user => some_user_interested_in_the_event, :source => new_friendship
72
+
73
+ If you want the enable/disable event feature to work (a.k.a. privacy settings), the source must implement a user method which returns the user who caused the event. That user's privacy settings are then check before creating the actual FeedEvent instance.
74
+
75
+ Warning: Do not create events using create! but use the create method (without the bang) - when a user has not subscribed to an event, a validation in the FeedEvent class will fail so that the event won't be created. If you use the create! method you will get an exception instead.
76
+
77
+ Configuration
78
+ =============
79
+
80
+ You can setup the from address used by the FeedEventMailers create_event_message method in the social_feed.yml in your config folder.
81
+
82
+ Gotchas
83
+ =======
84
+
85
+ For all models of you application you use as a source for a FeedEvent, add a
86
+ :has_many :feed_events, :dependent => :destroy
87
+ so that the feed events are destroyed when objects are destroyed. Otherwise the social feeds of you users will get into trouble with sources of events missing.
88
+
89
+
90
+
91
+ Contact
92
+ =======
93
+
94
+ Copyright (c) 2008 Alexander Lang, released under the MIT license
95
+
96
+ Contact: email: alex[at]upstream-berlin.com, twitter: langalex, blog: http://upstream-berlin.com/blog, skype: langalex
@@ -0,0 +1,24 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ desc 'Default: run specs.'
5
+ task :default => :spec
6
+
7
+ desc "Run all specs"
8
+ Spec::Rake::SpecTask.new(:spec) do |t|
9
+ t.spec_files = FileList['spec/**/*_spec.rb']
10
+ end
11
+
12
+ begin
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gemspec|
15
+ gemspec.name = "social_feed"
16
+ gemspec.summary = "a ruby on rails plugin to create and display a social feed"
17
+ gemspec.email = "alex@upstream-berlin.com"
18
+ gemspec.homepage = "http://github.com/langalex/social_feed"
19
+ gemspec.description = ""
20
+ gemspec.authors = ["Alexander Lang", "Thilo Utke"]
21
+ end
22
+ rescue LoadError
23
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
24
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,19 @@
1
+ class FeedEventGenerator < Rails::Generator::Base
2
+
3
+ attr_accessor :event_name
4
+
5
+ def initialize(runtime_args, runtime_options = {})
6
+ super
7
+ self.event_name = runtime_args[0]
8
+ raise "Usage: script/generate feed_event <event_name>\ne.g. script/generate feed_event user_signed_up\n" unless event_name
9
+ end
10
+
11
+ def manifest
12
+ record do |r|
13
+ r.template 'event_model.rb.erb', "app/models/events/#{event_name.underscore}_event.rb"
14
+ r.template 'event_hint.html.erb', "app/views/feed_events/_#{event_name.underscore}_hint.html.erb"
15
+ # email template and mailer method
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,4 @@
1
+ <div id="<%%= dom_id(event) %>" class="feed_event">
2
+ A <%= event_name.humanize %> event occured.
3
+ <%%= link_to_remote 'Destroy', :url => feed_event_path(event), :method => :delete %>
4
+ </div>
@@ -0,0 +1,5 @@
1
+ class <%= event_name.camelize %>Event < FeedEvent
2
+ subscribe_description 'A <%= event_name.humanize %> event occurs'
3
+ privacy_description 'I cause a <%= event_name.humanize %> event'
4
+
5
+ end
@@ -0,0 +1,13 @@
1
+ class SocialFeedMigrationGenerator < Rails::Generator::Base
2
+
3
+ def manifest
4
+ record do |r|
5
+ r.migration_template 'migration.rb', "db/migrate"
6
+ end
7
+ end
8
+
9
+ def file_name
10
+ "add_social_feed"
11
+ end
12
+
13
+ end
@@ -0,0 +1,24 @@
1
+ class AddSocialFeed < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :users, :feed_event_subscriptions, :text
4
+ add_column :users, :email_subscriptions, :text
5
+ add_column :users, :enabled_feed_events, :text
6
+
7
+ create_table :feed_events do |t|
8
+ t.column :type, :string
9
+ t.column :user_id, :integer
10
+ t.column :created_at, :datetime
11
+ t.column :source_id, :integer
12
+ t.column :source_type, :string
13
+ t.column :hint_body, :text
14
+ end
15
+ end
16
+
17
+ def self.down
18
+ remove_column :users, :feed_event_subscriptions
19
+ remove_column :users, :email_subscriptions
20
+ remove_column :users, :enabled_feed_events
21
+
22
+ drop_table :feed_events
23
+ end
24
+ end
data/init.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'object_extensions'
2
+
3
+ # configuration
4
+ require 'ostruct'
5
+ SocialFeed::Conf = OpenStruct.new YAML::load(File.read(RAILS_ROOT + '/config/social_feed.yml'))
6
+
7
+
8
+ ActionController::Base.helper(SocialFeed::SocialFeedHelper)
9
+
10
+ ActionController::Routing::RouteSet::Mapper.send(:include, SocialFeed::Routing)
@@ -0,0 +1,35 @@
1
+ require 'fileutils'
2
+
3
+ __DIR__ = File.dirname(__FILE__)
4
+ RAILS_ROOT = __DIR__ + '/../../..'
5
+
6
+ # generate migration
7
+ # done by user
8
+
9
+ # add events directory to load path
10
+ # done by user
11
+
12
+ # create events directory
13
+ FileUtils.mkdir RAILS_ROOT + '/app/models/events'
14
+
15
+ # copy mailer template
16
+ FileUtils.cp __DIR__ + '/lib/feed_event_mailer.rb.template', RAILS_ROOT + '/app/models/feed_event_mailer.rb'
17
+
18
+ # create mailer views directory
19
+ FileUtils.mkdir RAILS_ROOT + '/app/views/feed_event_mailer'
20
+
21
+ # copy controller views, partials
22
+ FileUtils.mkdir RAILS_ROOT + '/app/views/feed_events'
23
+ FileUtils.cp __DIR__ + '/lib/feed_events_controller.rb.template', RAILS_ROOT + '/app/controllers/feed_events_controller.rb'
24
+ FileUtils.cp __DIR__ + '/views/index.html.erb', RAILS_ROOT + '/app/views/feed_events'
25
+ FileUtils.cp __DIR__ + '/views/settings.html.erb', RAILS_ROOT + '/app/views/feed_events'
26
+ FileUtils.cp __DIR__ + '/views/destroy.rjs', RAILS_ROOT + '/app/views/feed_events'
27
+ FileUtils.cp __DIR__ + '/views/_user_feed.html.erb', RAILS_ROOT + '/app/views/feed_events'
28
+
29
+ # copy config file
30
+ FileUtils.cp __DIR__ + '/social_feed.yml', RAILS_ROOT + '/config'
31
+
32
+ # add routes
33
+ # done by user
34
+
35
+ puts File.read(__DIR__ + '/INSTALL')
@@ -0,0 +1,81 @@
1
+ class FeedEvent < ActiveRecord::Base
2
+ def before_validation_on_create
3
+ send_email
4
+ end
5
+
6
+ belongs_to :source, :polymorphic => true
7
+ validates_presence_of :user_id #receiver
8
+ validate :source_user_has_event_enabled
9
+ validate :user_has_subscribed_to_event
10
+
11
+ @@event_types = []
12
+
13
+ belongs_to :user
14
+
15
+ def allowed_to_destroy?(_user_id)
16
+ (user_id == _user_id)
17
+ end
18
+
19
+ def self.event_types
20
+ load_subclasses if @@event_types.empty?
21
+ @@event_types
22
+ end
23
+
24
+ def self.subscribable_feed_event_types
25
+ event_types.reject{|type| type.user_cannot_subscribe_to_event?}
26
+ end
27
+
28
+ def self.enabable_feed_event_types
29
+ event_types.select{|type| type.user_can_enable_event?}
30
+ end
31
+
32
+ def self.subscribe_description(desc = nil)
33
+ @@subscribe_descriptions ||= {}
34
+ @@subscribe_descriptions[name] = desc if desc
35
+ @@subscribe_descriptions[name]
36
+ end
37
+
38
+ def self.privacy_description(desc = nil)
39
+ @@privacy_descriptions ||= {}
40
+ @@privacy_descriptions[name] = desc if desc
41
+ @@privacy_descriptions[name]
42
+ end
43
+
44
+ def self.can_send_email?
45
+ FeedEventMailer.send(:new).respond_to?(name.underscore[0..-7])
46
+ end
47
+
48
+ def self.user_cannot_subscribe_to_event?
49
+ subscribe_description.blank?
50
+ end
51
+
52
+ def self.user_can_enable_event?
53
+ privacy_description
54
+ end
55
+
56
+ private
57
+
58
+ def source_disabled_event?
59
+ self.class.user_can_enable_event? && source.respond_to?(:user) && source.user && !source.user.feed_event_enabled?(self.class)
60
+ end
61
+ def send_email
62
+ FeedEventMailer.send "deliver_#{self.class.name.underscore[0..-7]}", self if self.class.can_send_email? &&
63
+ (user.subscribed_to_email?(self.class) || self.class.user_cannot_subscribe_to_event?) && !user.try(:online?) && !source_disabled_event?
64
+ end
65
+
66
+ def self.load_subclasses
67
+ Dir[RAILS_ROOT+'/app/models/events/*_event.rb'].each do |file|
68
+ @@event_types << File.basename(file, '.rb').camelize.constantize
69
+ end
70
+ end
71
+
72
+ def user_has_subscribed_to_event
73
+ errors.add :user, "has not subscribed to event #{self.class}" unless user.if_not_nil?{|u| u.subscribed_to_feed_event?(self.class)} ||
74
+ self.class.user_cannot_subscribe_to_event?
75
+ end
76
+
77
+ def source_user_has_event_enabled
78
+ errors.add :source, "this event is disabled by the user of #{self.source.class}" if source_disabled_event?
79
+ end
80
+
81
+ end
@@ -0,0 +1,6 @@
1
+ class FeedEventMailer < ActionMailer::Base
2
+ include SocialFeed::FeedEventMailerExtension
3
+
4
+ # add your emails here or use the generator to generate stubs
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ class FeedEventsController < ApplicationController
2
+ include SocialFeed::FeedEventsControllerExtension
3
+
4
+ # add your custom methods here
5
+
6
+ end
@@ -0,0 +1,27 @@
1
+ class Object
2
+ def try(method, *params)
3
+ send method, *params if respond_to? method
4
+ end
5
+ end
6
+
7
+ class Object
8
+ def if_nil?
9
+ self
10
+ end
11
+
12
+ def if_not_nil?
13
+ yield self
14
+ end
15
+ end
16
+
17
+ class NilClass
18
+ def if_nil?
19
+ yield self
20
+ self
21
+ end
22
+
23
+ def if_not_nil?
24
+ self
25
+ end
26
+ end
27
+
@@ -0,0 +1,14 @@
1
+ module SocialFeed
2
+ module FeedEventMailerExtension
3
+
4
+ private
5
+ def create_event_message(subject, event)
6
+ @subject = subject
7
+ @body = {:event => event}
8
+ @recipients = event.user.email
9
+ @from = SocialFeed::Conf.sender_email
10
+ @sent_on = Time.now
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ module SocialFeed
2
+ module FeedEventsControllerExtension
3
+
4
+ def destroy
5
+ @event = current_user.feed_events.find params[:id]
6
+ @event.destroy
7
+ end
8
+
9
+ def index
10
+ @feed_events = current_user.feed_events.find :all, :limit => 20, :order => 'created_at DESC'
11
+ end
12
+
13
+ def settings
14
+
15
+ end
16
+
17
+ def toggle_subscription
18
+ if current_user.subscribed_to_feed_event?(params[:event])
19
+ current_user.unsubscribe_from_feed_event(params[:event])
20
+ else
21
+ current_user.subscribe_to_feed_event(params[:event])
22
+ end
23
+ current_user.save
24
+ render :nothing => true
25
+ end
26
+
27
+ def toggle_email_subscription
28
+ if current_user.subscribed_to_email?(params[:event])
29
+ current_user.unsubscribe_from_email(params[:event])
30
+ else
31
+ current_user.subscribe_to_email(params[:event])
32
+ end
33
+ current_user.save
34
+ render :nothing => true
35
+ end
36
+
37
+ def toggle_enabled
38
+ if current_user.feed_event_enabled? params[:event]
39
+ current_user.disable_feed_event params[:event]
40
+ else
41
+ current_user.enable_feed_event params[:event]
42
+ end
43
+ current_user.save
44
+ render :nothing => true
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,15 @@
1
+ module SocialFeed
2
+ module Routing
3
+ def from_plugin(name)
4
+ plugin_root = File.join(RAILS_ROOT,
5
+ 'vendor',
6
+ 'plugins')
7
+ routes_path = File.join(plugin_root,
8
+ name.to_s,
9
+ 'routes.rb')
10
+ if File.file?(routes_path)
11
+ eval(IO.read(routes_path), binding, routes_path)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module SocialFeed
2
+ module SocialFeedHelper
3
+ def feed_event_partial_name(event)
4
+ event.class.name.underscore.sub(/event$/, 'hint')
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,59 @@
1
+ module SocialFeed
2
+ module UserExtension
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ serialize :feed_event_subscriptions
7
+ serialize :email_subscriptions
8
+ serialize :enabled_feed_events
9
+
10
+ has_many :feed_events, :dependent => :destroy, :order => "id DESC"
11
+ has_many :feed_events_as_source, :dependent => :destroy, :as => :source, :class_name => 'FeedEvent'
12
+ end
13
+
14
+ end
15
+
16
+ def subscribe_to_feed_event(event_class)
17
+ self.feed_event_subscriptions ||= []
18
+ self.feed_event_subscriptions |= [event_class.to_s]
19
+ end
20
+
21
+ def subscribed_to_feed_event?(event_class)
22
+ self.feed_event_subscriptions.if_not_nil?{|s| s.include?(event_class.to_s)}
23
+ end
24
+
25
+ def unsubscribe_from_feed_event(event_class)
26
+ self.feed_event_subscriptions_will_change!
27
+ self.feed_event_subscriptions.delete event_class.to_s
28
+ end
29
+
30
+ def subscribe_to_email(event_class)
31
+ self.email_subscriptions ||= []
32
+ self.email_subscriptions |= [event_class.to_s]
33
+ end
34
+
35
+ def subscribed_to_email?(event_class)
36
+ self.email_subscriptions.if_not_nil?{|s| s.include?(event_class.to_s)}
37
+ end
38
+
39
+ def unsubscribe_from_email(event_class)
40
+ self.email_subscriptions_will_change!
41
+ self.email_subscriptions.delete event_class.to_s
42
+ end
43
+
44
+ def enable_feed_event(event_class)
45
+ self.enabled_feed_events ||= []
46
+ self.enabled_feed_events |= [event_class.to_s]
47
+ end
48
+
49
+ def disable_feed_event(event_class)
50
+ self.enabled_feed_events_will_change!
51
+ self.enabled_feed_events.delete event_class.to_s
52
+ end
53
+
54
+ def feed_event_enabled?(event_class)
55
+ self.enabled_feed_events.if_not_nil?{|e| e.include? event_class.to_s}
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,2 @@
1
+ resources :feed_events, :collection => {:toggle_subscription => :post, :toggle_email_subscription => :post, :toggle_enabled => :post,
2
+ :settings => :get}
@@ -0,0 +1 @@
1
+ sender_email: "<no-reply@mydomain.com>"
@@ -0,0 +1,103 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require PLUGIN_ROOT + '/lib/social_feed/feed_events_controller_extension'
3
+
4
+ class FeedEventsController
5
+ attr_accessor :params
6
+ include SocialFeed::FeedEventsControllerExtension
7
+
8
+ def render(options); end
9
+
10
+ end
11
+
12
+ describe FeedEventsController do
13
+
14
+ before(:each) do
15
+ @controller = FeedEventsController.new
16
+ end
17
+
18
+ def set_current_user(user)
19
+ @controller.stub!(:current_user).and_return(user)
20
+ end
21
+
22
+ def post(method, options)
23
+ @controller.params = options
24
+ @controller.send method
25
+ end
26
+
27
+
28
+ describe FeedEventsController, 'toggle enabled feed events' do
29
+ before(:each) do
30
+ @user = stub 'user', :feed_event_enabled? => false, :enable_feed_event => true, :save => true
31
+ set_current_user @user
32
+ end
33
+
34
+ it "should enable the event" do
35
+ @user.should_receive(:enable_feed_event).with('TestEvent')
36
+ post :toggle_enabled, :event => 'TestEvent'
37
+ end
38
+
39
+ it "should disable an enabled event" do
40
+ @user.stub!(:feed_event_enabled?).with('TestEvent').and_return(true)
41
+ @user.should_receive(:disable_feed_event).with('TestEvent')
42
+ post :toggle_enabled, :event => 'TestEvent'
43
+ end
44
+
45
+ it "should save the user" do
46
+ @user.should_receive(:save)
47
+ post :toggle_enabled, :event => 'TestEvent'
48
+ end
49
+
50
+ end
51
+
52
+ describe FeedEventsController, 'toggle subscribe to feed event' do
53
+ before(:each) do
54
+ @user = stub 'user', :subscribed_to_feed_event? => true, :unsubscribe_from_feed_event => false, :save => true
55
+ set_current_user @user
56
+ end
57
+
58
+ it "should subscribe on the event" do
59
+ @user.stub!(:subscribed_to_feed_event?).with('TestEvent').and_return(false)
60
+ @user.should_receive(:subscribe_to_feed_event).with('TestEvent')
61
+ post :toggle_subscription, :event => 'TestEvent'
62
+ end
63
+
64
+ it "should unsubscribe from a subscribed event" do
65
+ @user.stub!(:subscribed_to_feed_event?).with('TestEvent').and_return(true)
66
+ @user.should_receive(:unsubscribe_from_feed_event).with('TestEvent')
67
+ post :toggle_subscription, :event => 'TestEvent'
68
+ end
69
+
70
+ it "should save the user" do
71
+ @user.should_receive(:save)
72
+ post :toggle_subscription, :event => 'TestEvent'
73
+ end
74
+
75
+ end
76
+
77
+ describe FeedEventsController, 'toggle subscribe to email event' do
78
+ before(:each) do
79
+ @user = stub 'user', :subscribed_to_email? => true, :unsubscribe_from_email => nil, :save => true
80
+ set_current_user @user
81
+ end
82
+
83
+
84
+ it "should subscribe on the event" do
85
+ @user.stub!(:subscribed_to_email?).with('TestEvent').and_return(false)
86
+ @user.should_receive(:subscribe_to_email).with('TestEvent')
87
+ post :toggle_email_subscription, :event => 'TestEvent'
88
+ end
89
+
90
+ it "should unsubscribe from a subscribed event" do
91
+ @user.stub!(:subscribed_to_email?).with('TestEvent').and_return(true)
92
+ @user.should_receive(:unsubscribe_from_email).with('TestEvent')
93
+ post :toggle_email_subscription, :event => 'TestEvent'
94
+ end
95
+
96
+ it "should save the user" do
97
+ @user.should_receive(:save)
98
+ post :toggle_email_subscription, :event => 'TestEvent'
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require PLUGIN_ROOT + '/lib/social_feed/social_feed_helper'
3
+ include SocialFeed::SocialFeedHelper
4
+ class TestEvent; end
5
+ class TestEventCreatedEvent; end
6
+
7
+ describe SocialFeed::SocialFeedHelper do
8
+
9
+ it "should derive the hint partial from the feed class" do
10
+ feed_event_partial_name(TestEvent.new).should == 'test_hint'
11
+ end
12
+
13
+ it "should only replace event with hint at the end" do
14
+ feed_event_partial_name(TestEventCreatedEvent.new).should == 'test_event_created_hint'
15
+ end
16
+
17
+ end
@@ -0,0 +1,202 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require PLUGIN_ROOT + '/lib/feed_event'
3
+
4
+ describe FeedEvent, 'send emails' do
5
+ class TestFeedEvent < FeedEvent; end
6
+
7
+ it "should send no email if mailer does not support it" do
8
+ user = mock_model(User, :subscribed_to_feed_event? => true)
9
+ event = TestFeedEvent.new :source => user, :user => user
10
+ FeedEventMailer.should_receive(:deliver_test_feed_event).never
11
+ event.save!
12
+ end
13
+
14
+ it "should derive mailer method from class name" do
15
+ FeedEventMailer.stub!(:send).with(:new).and_return(stub('mailer', :test_feed => true))
16
+ user = mock_model User, :subscribed_to_feed_event? => true, :subscribed_to_email? => true, :online? => false
17
+ event = TestFeedEvent.new :source => user, :user => user
18
+ FeedEventMailer.should_receive(:send).with('deliver_test_feed', event)
19
+ event.save!
20
+ end
21
+
22
+ it "should not be able to send mail if mailer has no mailer method" do
23
+ TestFeedEvent.can_send_email?.should be_false
24
+ end
25
+
26
+ it "should be able to send mail if mailer has mailer method" do
27
+ FeedEventMailer.stub!(:new).and_return(nil) # actionmailer.new really returns nil, you have to use send(:new)
28
+ FeedEventMailer.stub!(:send).with(:new).and_return(stub('mailer', :test_feed => true))
29
+ TestFeedEvent.can_send_email?.should be_true
30
+ end
31
+ end
32
+
33
+ describe FeedEvent, 'check event enabled when creating' do
34
+
35
+ class TestFeedEvent < FeedEvent
36
+ privacy_description 'desc'
37
+ end
38
+ class NotDisabableEvent < FeedEvent; end
39
+
40
+ before(:each) do
41
+ @user = mock_model User, :feed_event_enabled? => true
42
+ @event = TestFeedEvent.new :source => mock_model(FeedEvent, :user => @user)
43
+ end
44
+
45
+ it "should be valid if source user has event enabled" do
46
+ @event.valid?
47
+ @event.should have(:no).errors_on(:source)
48
+ end
49
+
50
+ it "should be invalid if soure user has event disabled" do
51
+ @user.stub!(:feed_event_enabled?).and_return(false)
52
+ @event.valid?
53
+ @event.should have(1).error_on(:source)
54
+ end
55
+
56
+ it "should check wether the event is enabled" do
57
+ @user.should_receive(:feed_event_enabled?).with(TestFeedEvent)
58
+ @event.valid?
59
+ end
60
+
61
+ it "should be valid if source has no user" do
62
+ @event.source = mock_model(FeedEvent)
63
+ @event.valid?
64
+ @event.should have(:no).errors_on(:source)
65
+ end
66
+
67
+ it "should be valid if source user is nil" do
68
+ @event.source = mock_model(FeedEvent, :user => nil)
69
+ @event.valid?
70
+ @event.should have(:no).errors_on(:source)
71
+ end
72
+
73
+ it "should be valid if source user has event disabled but event has no privacy description (user can not disabled the event)" do
74
+ @user.stub!(:feed_event_enabled?).and_return(false)
75
+ event = NotDisabableEvent.new :source => mock_model(FeedEvent, :user => @user)
76
+ event.valid?
77
+ event.should have(:no).errors_on(:source)
78
+ end
79
+
80
+ end
81
+
82
+ describe 'check event enabled when sending email' do
83
+ class TestFeedEvent < FeedEvent
84
+ privacy_description 'desc'
85
+ end
86
+
87
+ class NotDisabableEvent < FeedEvent;end
88
+
89
+ class Source; end
90
+
91
+ before(:each) do
92
+ TestFeedEvent.connection.stub!(:insert)
93
+ FeedEventMailer.stub!(:send).with(:new).and_return(stub('mailer', :test_feed => true, :not_disabable => true))
94
+ @user = mock_model(User, :subscribed_to_feed_event? => true, :subscribed_to_email? => true)
95
+ Source.stub!(:base_class).and_return(Source)
96
+ @source = mock_model(Source, :user => @user)
97
+ @event = TestFeedEvent.new :source => @source, :user => @user
98
+ end
99
+
100
+ it "should send no email if event disabled" do
101
+ @user.stub!(:feed_event_enabled?).and_return(false)
102
+ FeedEventMailer.should_receive(:send).with('deliver_test_feed', @event).never
103
+ @event.save
104
+ end
105
+
106
+ it "should send email if event enabled" do
107
+ @user.stub!(:feed_event_enabled?).and_return(true)
108
+ FeedEventMailer.should_receive(:send).with('deliver_test_feed', @event)
109
+ @event.save
110
+ end
111
+
112
+ it "should send email if user can't disable event" do
113
+ event = NotDisabableEvent.new :source => @source, :user => @user
114
+ FeedEventMailer.should_receive(:send).with('deliver_not_disabable', event)
115
+ event.save
116
+ end
117
+ end
118
+ describe FeedEvent, 'check subscriptions when creating' do
119
+ class TestFeedEvent < FeedEvent
120
+ subscribe_description 'desc'
121
+ end
122
+ class NotSubscribableEvent < FeedEvent; end
123
+
124
+ before(:each) do
125
+ @user = mock_model User
126
+ @event = TestFeedEvent.new :user => @user
127
+ end
128
+
129
+ it "should be invalid if user not subscribed to event" do
130
+ @user.stub!(:subscribed_to_feed_event?).and_return(false)
131
+ @event.valid?
132
+ @event.should have(1).errors_on(:user)
133
+ end
134
+
135
+ it "should be valid if user not subscribed to event but event has no description (user could not unsubscribe from this event)" do
136
+ @user.stub!(:subscribed_to_feed_event?).and_return(false)
137
+ @event = NotSubscribableEvent.new :user => @user
138
+ @event.should have(:no).errors_on(:user)
139
+ end
140
+
141
+ it "should check the subscription of the user" do
142
+ @user.should_receive(:subscribed_to_feed_event?).with(TestFeedEvent).and_return(true)
143
+ @event.valid?
144
+ end
145
+
146
+ it "should be valid if user subscribed to event" do
147
+ @user.stub!(:subscribed_to_feed_event?).and_return(true)
148
+ @event.valid?
149
+ @event.should have(:no).errors_on(:user)
150
+ end
151
+ end
152
+
153
+ describe FeedEvent, 'check subscription before sending emails' do
154
+ class TestFeedEvent < FeedEvent
155
+ subscribe_description 'desc'
156
+ end
157
+ class NotSubscribableEvent < FeedEvent; end
158
+
159
+ before(:each) do
160
+ @user = mock_model User, :subscribed_to_email? => true, :subscribed_to_feed_event? => true, :online? => false
161
+ FeedEventMailer.stub!(:send).with(:new).and_return(stub('mailer', :respond_to? => true))
162
+ end
163
+
164
+ it "should send an email if user subscribed to email" do
165
+ FeedEventMailer.should_receive(:send).with('deliver_test_feed', anything)
166
+ TestFeedEvent.create :user => @user
167
+ end
168
+
169
+ it "should send no email if user subscribed to email but is online" do
170
+ @user.stub!(:online?).and_return(true)
171
+ FeedEventMailer.should_receive(:send).with('deliver_test_feed', anything).never
172
+ TestFeedEvent.create :user => @user
173
+ end
174
+
175
+ it "should send an email user user subscribed to email and has no online method" do
176
+ FeedEventMailer.should_receive(:send).with('deliver_test_feed', anything)
177
+ TestFeedEvent.create :user => mock_model(User, :subscribed_to_email? => true, :subscribed_to_feed_event? => false)
178
+ end
179
+
180
+ it "should check the subscription of the user" do
181
+ @user.should_receive(:subscribed_to_email?).with(TestFeedEvent).and_return(false)
182
+ TestFeedEvent.create :user => @user
183
+ end
184
+
185
+ it "should send no email if user has not subscribed to email" do
186
+ @user.stub!(:subscribed_to_email?).and_return(false)
187
+ FeedEventMailer.should_receive(:send).with('deliver_test_feed', anything).never
188
+ TestFeedEvent.create :user => @user
189
+ end
190
+
191
+ it "should send a email if user can't unsubscribe from email (event has no email description)" do
192
+ @user.stub!(:subscribed_to_email?).and_return(false)
193
+ FeedEventMailer.should_receive(:send).with('deliver_not_subscribable', anything)
194
+ NotSubscribableEvent.create :user => @user
195
+ end
196
+
197
+ it "should send an email if user subscribed to email but not to feed event" do
198
+ @user.stub!(:subscribed_to_feed_event?).and_return(false)
199
+ FeedEventMailer.should_receive(:send).with('deliver_test_feed', anything)
200
+ TestFeedEvent.create :user => @user
201
+ end
202
+ end
@@ -0,0 +1,148 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe User, 'enable feed events' do
4
+
5
+ class TestEvent; end
6
+ before(:each) do
7
+ @user = User.new
8
+ end
9
+
10
+ it "should enable an event" do
11
+ @user.enable_feed_event TestEvent
12
+ @user.enabled_feed_events.should include('TestEvent')
13
+ end
14
+
15
+ it "should enable an event only once" do
16
+ @user.enable_feed_event TestEvent
17
+ @user.enable_feed_event TestEvent
18
+ @user.enabled_feed_events.should == ['TestEvent']
19
+ end
20
+
21
+ it "should disable and event" do
22
+ @user.enabled_feed_events = ['TestEvent']
23
+ @user.disable_feed_event TestEvent
24
+ @user.enabled_feed_events.should_not include('TestEvent')
25
+ end
26
+
27
+ it "should return true if an event is enabled" do
28
+ @user.enabled_feed_events = ['TestEvent']
29
+ @user.should be_feed_event_enabled(TestEvent)
30
+ end
31
+
32
+ it "should return false if an event is disabled" do
33
+ @user.should_not be_feed_event_enabled(TestEvent)
34
+ end
35
+
36
+ it "should mark the attibute dirty when disabling" do
37
+ @user.enabled_feed_events = ['TestEvent']
38
+ @user.save!
39
+ @user.disable_feed_event TestEvent
40
+ @user.should be_enabled_feed_events_changed
41
+ end
42
+
43
+ it "should mark the attibute dirty when enabling" do
44
+ @user.enabled_feed_events = ['TestEvent1']
45
+ @user.save!
46
+ @user.enable_feed_event TestEvent
47
+ @user.should be_enabled_feed_events_changed
48
+ end
49
+ end
50
+
51
+ describe User, 'subscribe to feed events' do
52
+ class TestEvent; end
53
+ before(:each) do
54
+ @user = User.new
55
+ end
56
+
57
+ it "should subscribe to an event" do
58
+ @user.subscribe_to_feed_event TestEvent
59
+ @user.feed_event_subscriptions.should include('TestEvent')
60
+ end
61
+
62
+ it "should subscribe to an event only once" do
63
+ @user.subscribe_to_feed_event TestEvent
64
+ @user.subscribe_to_feed_event TestEvent
65
+ @user.feed_event_subscriptions.should == ['TestEvent']
66
+ end
67
+
68
+ it "should unsubscribe from an event" do
69
+ @user.feed_event_subscriptions = ['TestEvent']
70
+ @user.unsubscribe_from_feed_event TestEvent
71
+ @user.feed_event_subscriptions.should be_empty
72
+ end
73
+
74
+ it "should return true if user is subscribed" do
75
+ @user.feed_event_subscriptions = ['TestEvent']
76
+ @user.should be_subscribed_to_feed_event(TestEvent)
77
+ end
78
+
79
+ it "should return false if user is not subscribed" do
80
+ @user.should_not be_subscribed_to_feed_event(TestEvent)
81
+ end
82
+
83
+ it "should mark the attibute dirty when subscribing" do
84
+ @user.feed_event_subscriptions = ['TestEvent1']
85
+ @user.save!
86
+ @user.subscribe_to_feed_event TestEvent
87
+ @user.should be_feed_event_subscriptions_changed
88
+ end
89
+
90
+ it "should mark the attibute dirty when unsubscribing" do
91
+ @user.feed_event_subscriptions = ['TestEvent']
92
+ @user.save!
93
+ @user.unsubscribe_from_feed_event TestEvent
94
+ @user.should be_feed_event_subscriptions_changed
95
+ end
96
+
97
+ end
98
+
99
+ describe User, 'subscribe to emails' do
100
+ class TestEvent; end
101
+ before(:each) do
102
+ @user = User.new
103
+ end
104
+
105
+ it "should subscribe to an email" do
106
+ @user.subscribe_to_email TestEvent
107
+ @user.email_subscriptions.should include('TestEvent')
108
+ end
109
+
110
+ it "should subscribe to an email only once" do
111
+ @user.subscribe_to_email TestEvent
112
+ @user.subscribe_to_email TestEvent
113
+ @user.email_subscriptions.should == ['TestEvent']
114
+ end
115
+
116
+ it "should unsubscribe from an email" do
117
+ @user.email_subscriptions = ['TestEvent']
118
+ @user.unsubscribe_from_email TestEvent
119
+ @user.email_subscriptions.should be_empty
120
+ end
121
+
122
+ it "should return true if user is subscribed" do
123
+ @user.email_subscriptions = ['TestEvent']
124
+ @user.should be_subscribed_to_email(TestEvent)
125
+ end
126
+
127
+ it "should return false if user is not subscribed" do
128
+ @user.should_not be_subscribed_to_email(TestEvent)
129
+ end
130
+
131
+ it "should mark the attibute dirty when subscribing" do
132
+ @user.email_subscriptions = ['TestEvent1']
133
+ @user.save!
134
+ @user.subscribe_to_email TestEvent
135
+ @user.should be_email_subscriptions_changed
136
+ end
137
+
138
+ it "should mark the attibute dirty when unsubscribing" do
139
+ @user.email_subscriptions = ['TestEvent']
140
+ @user.save!
141
+ @user.unsubscribe_from_email TestEvent
142
+ @user.should be_email_subscriptions_changed
143
+ end
144
+ end
145
+
146
+
147
+ describe User, 'subscribed to email notification' do
148
+ end
@@ -0,0 +1,86 @@
1
+ PLUGIN_ROOT = File.dirname(__FILE__) + '/..'
2
+
3
+ require 'rubygems'
4
+ gem 'activerecord'
5
+ require 'activerecord'
6
+
7
+ __DIR__ = File.dirname __FILE__
8
+
9
+ FileUtils.rm_rf __DIR__ + '/../test.sqlite3'
10
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => File.join(File.dirname(__FILE__), '..', 'test.sqlite3')
11
+
12
+ # migrate
13
+
14
+ class CreateUsers < ActiveRecord::Migration
15
+ def self.up
16
+ create_table :users do |t|
17
+
18
+ end
19
+ end
20
+ end
21
+ CreateUsers.up
22
+
23
+ require PLUGIN_ROOT + '/lib/social_feed/user_extension'
24
+ class User < ActiveRecord::Base
25
+ include SocialFeed::UserExtension
26
+ end
27
+ class FeedEventMailer; end
28
+
29
+ require File.dirname(__FILE__) + '/../generators/social_feed_migration/templates/migration'
30
+ AddSocialFeed.up
31
+
32
+ require PLUGIN_ROOT + '/lib/object_extensions'
33
+
34
+
35
+ # rspec rails stuff
36
+
37
+ module Spec
38
+ module Example
39
+ class ExampleGroup
40
+
41
+ @@model_id = 1000
42
+
43
+ def mock_model(model_class, options_and_stubs = {})
44
+ # null = options_and_stubs.delete(:null_object)
45
+ # stubs = options_and_stubs
46
+ id = @@model_id
47
+ @@model_id += 1
48
+ options_and_stubs = {
49
+ :id => id,
50
+ :to_param => id.to_s,
51
+ :new_record? => false,
52
+ :errors => stub("errors", :count => 0)
53
+ }.merge(options_and_stubs)
54
+ m = mock("#{model_class.name}_#{id}", options_and_stubs)
55
+ m.send(:__mock_proxy).instance_eval <<-CODE
56
+ def @target.is_a?(other)
57
+ #{model_class}.ancestors.include?(other)
58
+ end
59
+ def @target.kind_of?(other)
60
+ #{model_class}.ancestors.include?(other)
61
+ end
62
+ def @target.instance_of?(other)
63
+ other == #{model_class}
64
+ end
65
+ def @target.class
66
+ #{model_class}
67
+ end
68
+ CODE
69
+ yield m if block_given?
70
+ m
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ module ActiveRecord #:nodoc:
77
+ class Base
78
+
79
+ def errors_on(attribute)
80
+ self.valid?
81
+ [self.errors.on(attribute)].flatten.compact
82
+ end
83
+ alias :error_on :errors_on
84
+
85
+ end
86
+ end
@@ -0,0 +1,12 @@
1
+ <div id="user_feed">
2
+ <%- user_feed.each do |event| -%>
3
+ <%- if event.hint_body? -%>
4
+ <%= event.hint_body %>
5
+ <%- else -%>
6
+ <%= hint = render :partial => feed_event_partial_name(event), :locals => {:event => event}
7
+ event.update_attribute :hint_body, hint
8
+ hint
9
+ %>
10
+ <%- end -%>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1 @@
1
+ page.visual_effect :fade, dom_id(@event)
@@ -0,0 +1,2 @@
1
+ <%= link_to 'Settings', settings_feed_events_path %>
2
+ <%= render :partial => 'feed_events/user_feed', :object => @feed_events %>
@@ -0,0 +1,36 @@
1
+ <h2>Subscriptions</h2>
2
+ <table>
3
+ <tr>
4
+ <th>Feed</th>
5
+ <th>Email</th>
6
+ <th>Event</th>
7
+ </tr>
8
+ <%- FeedEvent.subscribable_feed_event_types.each do |clazz| -%>
9
+ <tr id="<%= clazz.name + '_row' %>">
10
+ <td>
11
+ <%= check_box_tag clazz.name + '_feed', '1', current_user.subscribed_to_feed_event?(clazz) %>
12
+ <%= observe_field clazz.name + '_feed', :url => toggle_subscription_feed_events_path(:event => clazz.name), :success => "new Effect.Highlight('#{clazz.name + '_row'}')" %>
13
+ </td>
14
+ <td>
15
+ <%- if clazz.can_send_email? -%>
16
+ <%= check_box_tag clazz.name + '_mail', '1', current_user.subscribed_to_email?(clazz) %>
17
+ <%= observe_field clazz.name + '_mail', :url => toggle_email_subscription_feed_events_path(:event => clazz.name), :success => "new Effect.Highlight('#{clazz.name + '_row'}')" %>
18
+ <%- end -%>
19
+ </td>
20
+ <td class="blue_font"><%= clazz.subscribe_description %></td>
21
+ </tr>
22
+ <%- end -%>
23
+ </table>
24
+
25
+ <h2>Privacy Settings</h2>
26
+ <table>
27
+ <%- FeedEvent.enabable_feed_event_types.each do |clazz| -%>
28
+ <tr id="<%= "#{clazz.name + '_privacy_row'}" %>">
29
+ <td>
30
+ <%= check_box_tag clazz.name + '_privacy', '1', current_user.feed_event_enabled?(clazz) %>
31
+ <%= observe_field clazz.name + '_privacy', :url => toggle_enabled_feed_events_path(:event => clazz.name), :success => "new Effect.Highlight('#{clazz.name + '_privacy_row'}')" %>
32
+ </td>
33
+ <td><%= clazz.privacy_description %></td>
34
+ </tr>
35
+ <%- end -%>
36
+ </table>
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: social_feed
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Lang
8
+ - Thilo Utke
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-05-07 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: ""
18
+ email: alex@upstream-berlin.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - README
25
+ files:
26
+ - .gitignore
27
+ - INSTALL
28
+ - MIT-LICENSE
29
+ - README
30
+ - Rakefile
31
+ - VERSION
32
+ - generators/feed_event/feed_event_generator.rb
33
+ - generators/feed_event/templates/event_hint.html.erb
34
+ - generators/feed_event/templates/event_model.rb.erb
35
+ - generators/social_feed_migration/social_feed_migration_generator.rb
36
+ - generators/social_feed_migration/templates/migration.rb
37
+ - init.rb
38
+ - install.rb
39
+ - lib/feed_event.rb
40
+ - lib/feed_event_mailer.rb.template
41
+ - lib/feed_events_controller.rb.template
42
+ - lib/object_extensions.rb
43
+ - lib/social_feed/feed_event_mailer_extension.rb
44
+ - lib/social_feed/feed_events_controller_extension.rb
45
+ - lib/social_feed/routing.rb
46
+ - lib/social_feed/social_feed_helper.rb
47
+ - lib/social_feed/user_extension.rb
48
+ - routes.rb
49
+ - social_feed.yml
50
+ - spec/controllers/feed_events_controller_spec.rb
51
+ - spec/helpers/social_feed_helper_spec.rb
52
+ - spec/models/feed_event_spec.rb
53
+ - spec/models/user_spec.rb
54
+ - spec/spec_helper.rb
55
+ - views/_user_feed.html.erb
56
+ - views/destroy.rjs
57
+ - views/index.html.erb
58
+ - views/settings.html.erb
59
+ has_rdoc: true
60
+ homepage: http://github.com/langalex/social_feed
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --charset=UTF-8
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.3.5
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: a ruby on rails plugin to create and display a social feed
87
+ test_files:
88
+ - spec/controllers/feed_events_controller_spec.rb
89
+ - spec/helpers/social_feed_helper_spec.rb
90
+ - spec/models/feed_event_spec.rb
91
+ - spec/models/user_spec.rb
92
+ - spec/spec_helper.rb