aitor-tog_social 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,112 @@
1
+ # Friendship objects represents the relation between two different members of the social network. The cardinality of the relationship is based on "inviter" and "invited" fields
2
+ # that store who started the relationship and who is the _passive_ subject of the relationship.
3
+ #
4
+ # If you have two profiles, tom and jerry, the following combinations can take place:
5
+ #
6
+ # inviter invited status
7
+ # ------- ------- -------
8
+ # tom jerry pending tom is a follower of jerry OR jerry is followed by tom OR jerry is a 'following' of tom
9
+ # jerry tom pending jerry is a follower of tom OR tom is followed by jerry OR tom is a 'following' of jerry
10
+ #
11
+ # jerry tom accept | | jerry "begun" the friendship
12
+ # or | jerry and tom are friends |
13
+ # jerry tom accept | | tom "begun" the friendship
14
+ class Friendship < ActiveRecord::Base
15
+ belongs_to :inviter, :class_name => 'Profile'
16
+ belongs_to :invited, :class_name => 'Profile'
17
+
18
+ PENDING = 0
19
+ ACCEPTED = 1
20
+
21
+ def validate
22
+ errors.add('inviter', 'inviter and invited can not be the same user') if invited == inviter
23
+ end
24
+ class << self
25
+
26
+ # Create a new follower of the +inviter+ user. Returns boolean value indicating if the relationship
27
+ # correctly created.
28
+ #
29
+ # ==== Options
30
+ #
31
+ # +inviter+ +Profile+ if the person that wants to be a follower if +invited+
32
+ #
33
+ # +invited+ +Profile+ of the user followed by +inviter+
34
+ #
35
+ def add_follower(inviter, invited)
36
+ a = Friendship.create(:inviter => inviter, :invited => invited, :status => PENDING)
37
+ !a.new_record?
38
+ end
39
+
40
+ # Create a friendship between the user and the target. Returns boolean value indicating if
41
+ # the relationship was correctly created.
42
+ #
43
+ # ==== Options
44
+ #
45
+ # +user+ +Profile+ or +User+ that purpose the friendship
46
+ #
47
+ # +target+ +Profile+ or +User+ that receives the purposement relationship
48
+ #
49
+ def make_friends(user, target)
50
+ transaction do
51
+ user = profile_of(user)
52
+ target = profile_of(target)
53
+ begin
54
+ find_friendship(user, target, PENDING).update_attribute(:status, ACCEPTED)
55
+ Friendship.create!(:inviter_id => target.id, :invited_id => user.id, :status => ACCEPTED)
56
+ rescue Exception
57
+ return make_friends(target, user) if user.followed_by? target
58
+ return add_follower(user, target)
59
+ end
60
+ end
61
+ true
62
+ end
63
+
64
+ def stop_being_friends(user, target)
65
+ transaction do
66
+ begin
67
+ find_friendship(target, user, ACCEPTED).update_attribute(:status, PENDING)
68
+ find_friendship(user, target, ACCEPTED).destroy
69
+ rescue Exception
70
+ return false
71
+ end
72
+ end
73
+ true
74
+ end
75
+
76
+ def reset(user, target)
77
+ begin
78
+ find_friendship(user, target).destroy
79
+ find_friendship(target, user, ACCEPTED).update_attribute(:status, PENDING)
80
+ rescue Exception
81
+ return true
82
+ end
83
+ true
84
+ end
85
+
86
+ private
87
+
88
+ def find_friendship(inviter, invited, status)
89
+ conditions = {:inviter_id => inviter.id, :invited_id => invited.id}
90
+ conditions.merge!(:status => status) if status
91
+ Friendship.find(:first, :conditions => conditions)
92
+ end
93
+
94
+ end
95
+
96
+ def accept!
97
+ self.update_attribute(:status, ACCEPTED)
98
+ end
99
+
100
+ private
101
+ def profile_of(user)
102
+ profile = case user
103
+ when User
104
+ user.profile
105
+ when Profile
106
+ user
107
+ else
108
+ nil
109
+ end
110
+ end
111
+
112
+ end
@@ -0,0 +1,97 @@
1
+ class Group < ActiveRecord::Base
2
+
3
+ belongs_to :author, :class_name => 'User', :foreign_key => 'user_id'
4
+
5
+ has_many :memberships
6
+
7
+ has_many :moderator_memberships, :class_name => 'Membership',
8
+ :conditions => ['memberships.moderator = ?', true]
9
+
10
+ has_many :members, :through => :memberships, :source => :user,
11
+ :conditions => ['memberships.state = ?', 'active']
12
+
13
+ has_many :pending_members, :through => :memberships, :source => :user,
14
+ :conditions => ['memberships.state = ?', 'pending']
15
+
16
+ has_many :moderators, :through => :moderator_memberships, :source => :user,
17
+ :conditions => ['memberships.state = ?', 'active']
18
+
19
+
20
+ #file_column :image, :root_path => File.join(RAILS_ROOT, "public/system/group_photos"), :web_root => 'system/group_photos/', :magick => {
21
+ # :versions => {
22
+ # :big => {:crop => "1:1", :size => Tog::Config["system.group.image.versions.big"], :name => "big"},
23
+ # :medium => {:crop => "1:1", :size => Tog::Config["system.group.image.versions.medium"], :name => "medium"},
24
+ # :small => {:crop => "1:1", :size => Tog::Config["system.group.image.versions.small"], :name => "small" },
25
+ # :tiny => {:crop => "1:1", :size => Tog::Config["system.group.image.versions.tiny"], :name => "tiny" }
26
+ # }
27
+ #}
28
+
29
+ acts_as_state_machine :initial => :pending
30
+ state :pending, :enter => :make_activation_code
31
+ state :active, :enter => :do_activate
32
+ event :activate do
33
+ transitions :from => :pending, :to => :active
34
+ end
35
+
36
+ validates_uniqueness_of :name
37
+ validates_presence_of :name
38
+ validates_presence_of :author
39
+
40
+ def membership_of(user)
41
+ mem = memberships.select{|m| m.user == user}
42
+ return mem.first unless mem.blank?
43
+ end
44
+
45
+ def activate_membership(user)
46
+ mem = membership_of(user)
47
+ mem.activate! if mem && mem.pending?
48
+ end
49
+
50
+ def grant_moderator(user)
51
+ moderator_privileges(user,true)
52
+ end
53
+
54
+ def revoke_moderator(user)
55
+ moderator_privileges(user,false)
56
+ end
57
+
58
+ def moderator_privileges(user, grant=false)
59
+ mem = membership_of(user)
60
+ mem.moderator = grant
61
+ mem.save!
62
+ end
63
+
64
+ def join(user,moderator=false)
65
+ # todo Confirm what to do if th user is already a member. By now just ignore it and continue.
66
+ mem = membership_of(user)
67
+ mem = self.memberships.build(:user => user) unless mem
68
+ mem.save!
69
+ mem.activate! unless self.moderated?
70
+ end
71
+
72
+ def leave(user)
73
+ mem = membership_of(user)
74
+ mem.destroy if mem
75
+ end
76
+
77
+ def is_banned(user)
78
+ raise "Implement this..."
79
+ end
80
+
81
+ def ban(user)
82
+ raise "Implement this..."
83
+ end
84
+
85
+
86
+ protected
87
+ def make_activation_code
88
+ self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
89
+ end
90
+
91
+ def do_activate
92
+ self.activated_at = Time.now.utc
93
+ self.activation_code = nil
94
+ self.moderator_memberships.each{|mod| mod.activate!}
95
+ end
96
+
97
+ end
@@ -0,0 +1,25 @@
1
+ class Membership < ActiveRecord::Base
2
+ belongs_to :group
3
+ belongs_to :user
4
+
5
+ acts_as_state_machine :initial => :pending
6
+
7
+ state :pending, :enter => :make_activation_code
8
+ state :active, :enter => :do_activate
9
+
10
+ event :activate do
11
+ transitions :from => :pending, :to => :active
12
+ end
13
+
14
+ protected
15
+
16
+ def make_activation_code
17
+ self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
18
+ end
19
+
20
+ def do_activate
21
+ self.activated_at = Time.now.utc
22
+ self.activation_code = nil
23
+ end
24
+
25
+ end
@@ -0,0 +1,117 @@
1
+ class Profile < ActiveRecord::Base
2
+ belongs_to :user
3
+
4
+ #file_column :icon, :root_path => File.join(RAILS_ROOT, "public/system/profile"), :web_root => 'system/profile/', :magick => {
5
+ # :versions => {
6
+ # :big => {:crop => "1:1", :size => Tog::Config["system.profile.image.versions.big"], :name => "big"},
7
+ # :medium => {:crop => "1:1", :size => Tog::Config["system.profile.image.versions.medium"], :name => "medium"},
8
+ # :small => {:crop => "1:1", :size => Tog::Config["system.profile.image.versions.small"], :name => "small"},
9
+ # :tiny => {:crop => "1:1", :size => Tog::Config["system.profile.image.versions.tiny"], :name => "tiny"}
10
+ # }
11
+ #}
12
+
13
+ has_many :friendships_by_others, :class_name => "Friendship", :foreign_key => 'invited_id', :conditions => "status = #{Friendship::ACCEPTED}"
14
+ has_many :friendships_by_me, :class_name => "Friendship", :foreign_key => 'inviter_id', :conditions => "status = #{Friendship::ACCEPTED}"
15
+
16
+ has_many :follower_friendships, :class_name => "Friendship", :foreign_key => "invited_id", :conditions => "status = #{Friendship::PENDING}"
17
+ has_many :following_friendships, :class_name => "Friendship", :foreign_key => "inviter_id", :conditions => "status = #{Friendship::PENDING}"
18
+
19
+ has_many :friends_by_others, :through => :friendships_by_others, :source => :inviter
20
+ has_many :friends_by_me, :through => :friendships_by_me, :source => :invited
21
+
22
+ has_many :followers, :through => :follower_friendships, :source => :inviter
23
+ has_many :followings, :through => :following_friendships, :source => :invited
24
+
25
+ before_create :set_default_icon
26
+
27
+
28
+ def friends
29
+ # Reload associations just to make sure we're working with the current staff. Bad smell!
30
+ # todo check this... if we don't should reload the relationship to get the test working...
31
+ (friends_by_others(true) + friends_by_me(true)).uniq
32
+ end
33
+ def friendships
34
+ (friendships_by_others(true) + friendships_by_me(true)).uniq
35
+ end
36
+
37
+ def full_name
38
+ #todo apply for internationalization
39
+ first_name.blank? && last_name.blank? ? self.user.login : "#{first_name} #{last_name}".strip
40
+ end
41
+
42
+ def followed_by? profile
43
+ followers(true).include? profile
44
+ end
45
+
46
+ def follows? profile
47
+ followings(true).include? profile
48
+ end
49
+ def is_friend_of? profile
50
+ friends.include? profile
51
+ end
52
+ def is_related_to? profile
53
+ me.followed_by?(profile) || me.follows?(profile) || me.is_friend_of?(profile)
54
+ end
55
+
56
+ def add_follower(follower)
57
+ if follower.follows? me
58
+ return false
59
+ elsif me.follows? follower
60
+ return add_friend(follower)
61
+ else
62
+ flw = Friendship.create(:inviter => follower, :invited => me, :status => Friendship::PENDING)
63
+ unless flw.new_record?
64
+ # todo enable send_friendships_notifications? setting per profile
65
+ # FriendshipMailer.deliver_new_follower(me, follower) if me.send_friendships_notifications?
66
+ FriendshipMailer.deliver_new_follower(me, follower)
67
+ return true
68
+ end
69
+ return false
70
+ end
71
+ end
72
+
73
+ def add_following(following)
74
+ following.add_follower(me)
75
+ end
76
+
77
+ def add_friend(friend)
78
+ relationship = if friend.follows? me
79
+ find_friendship(friend, me, Friendship::PENDING)
80
+ elsif friend.followed_by? me
81
+ find_friendship(me, friend, Friendship::PENDING)
82
+ else
83
+ Friendship.create(:inviter => friend, :invited => me, :status => Friendship::PENDING)
84
+ end
85
+ relationship.accept!
86
+ # todo enable send_friendships_notifications? setting per profile
87
+ # FriendshipMailer.deliver_frienship_validated(relationship.inviter, relationship.invited) if relationship.inviter.send_friendships_notifications?
88
+ FriendshipMailer.deliver_friendship_validated(relationship.inviter, relationship.invited)
89
+ return true
90
+ end
91
+ def remove_friend(friend)
92
+ relationships = me.friendships.select{|f| f.inviter == friend || f.invited == friend }
93
+ relationships.each{|r| r.destroy}
94
+ end
95
+
96
+
97
+ private
98
+ # Freud will be happy.
99
+ def me
100
+ self
101
+ end
102
+
103
+ def find_friendship(inviter, invited, status)
104
+ conditions = {:inviter_id => inviter.id, :invited_id => invited.id}
105
+ conditions.merge!(:status => status) if status
106
+ Friendship.find(:first, :conditions => conditions)
107
+ end
108
+ def set_default_icon
109
+ unless self.icon
110
+ if Tog::Config["system.profile.image.default"]
111
+ default_profile_icon = File.join(RAILS_ROOT, 'public', 'images', Tog::Config["system.profile.image.default"])
112
+ self.icon = File.new(default_profile_icon)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
@@ -0,0 +1,18 @@
1
+ class User < ActiveRecord::Base
2
+
3
+ has_one :profile, :dependent => :destroy
4
+ has_many :memberships
5
+ has_many :moderator_memberships, :class_name => 'Membership',
6
+ :conditions => ['memberships.moderator = ?', true]
7
+
8
+ has_many :groups, :through => :memberships,
9
+ :conditions => "memberships.state='active' and groups.state='active'"
10
+
11
+ has_many :moderated_groups, :through => :moderator_memberships,
12
+ :conditions => "memberships.state='active' and groups.state='active'", :source => :group
13
+
14
+ def name
15
+ profile.full_name
16
+ end
17
+
18
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ # Add your custom routes here. If in config/routes.rb you would
2
+ # add <tt>map.resources</tt>, here you would add just <tt>resources</tt>
3
+
4
+ # resources :tog_socials
@@ -0,0 +1,54 @@
1
+ class CreateTogSocialTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :profiles do |t|
4
+ t.integer :user_id
5
+ t.string :first_name
6
+ t.string :last_name
7
+ t.string :website
8
+ t.string :blog
9
+ t.string :icon
10
+ t.timestamps
11
+ end
12
+ User.find(:all).each{|u|
13
+ profile = Profile.new
14
+ profile.user = u
15
+ profile.save!
16
+ }
17
+
18
+ create_table :groups do |t|
19
+ t.string :name
20
+ t.string :description
21
+ t.string :image
22
+ t.string :state
23
+ t.boolean :private
24
+ t.boolean :moderated, :default => true
25
+ t.integer :user_id
26
+ t.string :activation_code, :limit => 40
27
+ t.datetime :activated_at
28
+ t.timestamps
29
+ end
30
+
31
+ create_table :memberships do |t|
32
+ t.integer :user_id
33
+ t.integer :group_id
34
+ t.boolean :moderator
35
+ t.string :state
36
+ t.string :activation_code, :limit => 40
37
+ t.datetime :activated_at
38
+ t.timestamps
39
+ end
40
+ create_table :friendships do |t|
41
+ t.integer :inviter_id
42
+ t.integer :invited_id
43
+ t.integer :status
44
+ t.timestamps
45
+ end
46
+ end
47
+
48
+ def self.down
49
+ drop_table :friendships
50
+ drop_table :memberships
51
+ drop_table :groups
52
+ drop_table :profiles
53
+ end
54
+ end
data/test/factories.rb ADDED
@@ -0,0 +1,16 @@
1
+ Factory.define :user do |u|
2
+ u.salt '7e3041ebc2fc05a40c60028e2c4901a81035d3cd'
3
+ u.crypted_password '00742970dc9e6319f8019fd54864d3ea740f04b1'
4
+ u.activation_code '8f24789ae988411ccf33ab0c30fe9106fab32e9a'
5
+ u.state 'pending'
6
+ u.email {|a| "#{a.login}@example.com".downcase }
7
+ end
8
+
9
+ Factory.define :profile do |u|
10
+ end
11
+
12
+
13
+ Factory.define :group do |g|
14
+ g.state 'active'
15
+ #g.author{|author| author.association :user, :login => 'chavez'}
16
+ end
@@ -0,0 +1,24 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
3
+ require 'test_help'
4
+ require 'test/unit'
5
+
6
+ require 'factory_girl'
7
+ require File.expand_path(File.dirname(__FILE__) + '/factories')
8
+
9
+ class Test::Unit::TestCase
10
+ self.use_transactional_fixtures = true
11
+ self.use_instantiated_fixtures = false
12
+ fixtures :all
13
+
14
+ def assert_difference(object, method = nil, difference = 1)
15
+ initial_value = object.send(method)
16
+ yield
17
+ assert_equal initial_value + difference, object.send(method), "#{object}##{method} should have a difference of #{difference}"
18
+ end
19
+
20
+ def assert_no_difference(object, method, &block)
21
+ assert_difference object, method, 0, &block
22
+ end
23
+
24
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GroupTest < Test::Unit::TestCase
4
+ context "A Group" do
5
+
6
+ setup do
7
+ @berlusconi = Factory(:user, :login => 'berlusconi')
8
+ @chavez = Factory(:user, :login => 'chavez')
9
+ @pornfans = Factory(:group, :name => 'Porn without frontiers', :moderated => false, :author => @chavez)
10
+ end
11
+
12
+ should "should allow to join directly" do
13
+ @pornfans.join(@berlusconi)
14
+ assert @pornfans.members.include?(@berlusconi), "The joined user should be on the members list"
15
+ end
16
+
17
+ should "allow give moderator rights" do
18
+ @pornfans.join(@berlusconi)
19
+ assert_no_difference(Membership, :count) do
20
+ @pornfans.grant_moderator(@berlusconi)
21
+ end
22
+ assert_contains @pornfans.moderators, @berlusconi
23
+ end
24
+
25
+ should "allow revoke moderator rights" do
26
+ @pornfans.join(@berlusconi)
27
+ assert_no_difference(Membership, :count) do
28
+ @pornfans.revoke_moderator(@berlusconi)
29
+ end
30
+ assert_does_not_contain @pornfans.moderators, @berlusconi
31
+ end
32
+
33
+ context "that is moderated" do
34
+ setup do
35
+ @selectedporn = Factory(:group, :name => 'Porn for V.I.P', :moderated => true, :author => @chavez)
36
+ end
37
+
38
+ should "not allow to join directly" do
39
+ assert_difference(Membership, :count) do
40
+ @selectedporn.join(@berlusconi)
41
+ end
42
+ assert !@selectedporn.members.include?(@berlusconi)
43
+ @selectedporn.activate_membership(@berlusconi)
44
+ assert @selectedporn.members(true).include?(@berlusconi)
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,78 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ProfileTest < Test::Unit::TestCase
4
+ context "A Profile " do
5
+ setup do
6
+ @user = Factory(:user, :login => 'chavez')
7
+ @user2 = Factory(:user, :login => 'evo')
8
+
9
+ @chavez = Factory(:profile, :first_name => 'Hugo', :last_name => 'Chavez', :user => @user)
10
+ @evo = Factory(:profile, :first_name => 'Evo', :last_name => 'Morales', :user => @user2)
11
+ end
12
+
13
+ should "returna full_name correctly base on first_name and last_name" do
14
+ assert_equal "Hugo Chavez", @chavez.full_name, "Full name should Hugo Chavez"
15
+ end
16
+
17
+ should "return last_name as full_name if first_name is blank" do
18
+ [nil, ""].each {|value|
19
+ @chavez.first_name = value
20
+ assert_equal "Chavez", @chavez.full_name, "Full name should Chavez if first name is blank"
21
+ }
22
+ end
23
+ should "return login as full_name if first name and last name are blank" do
24
+ [nil, ""].each {|value|
25
+ @chavez.first_name = @chavez.last_name = value
26
+ assert_equal "chavez", @chavez.full_name, "full_name should defaults to login if first name and last name are blank"
27
+ }
28
+ end
29
+
30
+ should "allow to add a follower" do
31
+ @chavez.add_follower(@evo)
32
+ assert @evo.follows?(@chavez), "Evo should follow Chavez"
33
+ assert @chavez.followed_by?(@evo), "Chavez should be followed by Evo"
34
+ end
35
+
36
+
37
+ def test_add_following
38
+ @evo.add_following(@chavez)
39
+ assert @evo.follows?(@chavez), "Evo should follow Chavez"
40
+ assert @chavez.followed_by?(@evo), "Chavez should be followed by Evo"
41
+ end
42
+
43
+ def test_add_follower_twice_has_no_effect
44
+ assert_difference(Friendship, :count) do
45
+ @chavez.add_follower(@evo)
46
+ end
47
+ assert_no_difference(Friendship, :count) do
48
+ @chavez.add_follower(@evo)
49
+ end
50
+ end
51
+
52
+
53
+ def test_add_follower_from_a_person_im_following_should_convert_the_relationship_on_a_friendship
54
+ @chavez.add_follower(@evo)
55
+ @evo.add_follower(@chavez)
56
+ assert @evo.is_friend_of?(@chavez)
57
+ assert @chavez.is_friend_of?(@evo)
58
+ end
59
+
60
+ def test_add_friend
61
+ assert !@evo.is_related_to?(@chavez)
62
+ assert @evo.add_friend(@chavez)
63
+ assert @evo.is_friend_of?(@chavez), "Evo and Chavez should be friends"
64
+ assert @chavez.is_friend_of?(@evo), "Chavez and Evo should be friends"
65
+ end
66
+
67
+ def test_remove_friend
68
+ assert @evo.add_friend(@chavez)
69
+ assert @evo.is_friend_of?(@chavez), "Evo and Chavez should be friends"
70
+ @evo.remove_friend(@chavez)
71
+ assert !@evo.is_friend_of?(@chavez)
72
+ assert !@evo.is_related_to?(@chavez)
73
+ end
74
+
75
+
76
+
77
+ end
78
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aitor-tog_social
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Aitor Garcia
8
+ - Roberto Salicio
9
+ - Alberto Molpeceres
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2008-04-24 00:00:00 -07:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: mime-types
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ description: Tog social
27
+ email: aitor@linkingpaths
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files: []
33
+
34
+ files:
35
+ - app/helpers
36
+ - app/models/friendship.rb
37
+ - app/models/group.rb
38
+ - app/models/membership.rb
39
+ - app/models/profile.rb
40
+ - app/models/user.rb
41
+ - app/views
42
+ - config/routes.rb
43
+ - db/migrate/001_create_tog_social_tables.rb
44
+ - tasks
45
+ - test/factories.rb
46
+ - test/test_helper.rb
47
+ - test/unit/group_test.rb
48
+ - test/unit/profile_test.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/aitor/tog_social
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --main
54
+ - README.txt
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.2.0
73
+ signing_key:
74
+ specification_version: 2
75
+ summary: tog_social
76
+ test_files: []
77
+