facteur 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +23 -0
  2. data/CHANGELOG +4 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +115 -0
  5. data/LICENSE +20 -20
  6. data/README.markdown +135 -137
  7. data/Rakefile +19 -41
  8. data/lib/facteur.rb +25 -14
  9. data/lib/facteur/active_record_addressee_model.rb +12 -0
  10. data/lib/facteur/active_record_mailbox_model.rb +15 -0
  11. data/lib/facteur/active_record_message_model.rb +24 -0
  12. data/lib/facteur/addressee_model.rb +29 -130
  13. data/lib/facteur/base_addressee_model.rb +163 -0
  14. data/lib/facteur/mailbox.rb +16 -0
  15. data/lib/facteur/mailbox_model.rb +9 -6
  16. data/lib/facteur/message.rb +16 -0
  17. data/lib/facteur/message_model.rb +16 -16
  18. data/lib/facteur/mongoid_addressee_model.rb +12 -0
  19. data/lib/facteur/mongoid_mailbox_model.rb +18 -0
  20. data/lib/facteur/mongoid_message_model.rb +19 -0
  21. data/lib/facteur/version.rb +3 -0
  22. data/lib/generators/facteur/install/install_generator.rb +25 -28
  23. data/lib/generators/facteur/install/templates/create_mailboxes.rb +14 -14
  24. data/lib/generators/facteur/install/templates/create_messages.rb +19 -19
  25. data/spec/activerecord/activerecord_spec_helper.rb +11 -0
  26. data/spec/activerecord/facteur_spec.rb +47 -0
  27. data/spec/mongoid/facteur_spec.rb +49 -0
  28. data/spec/mongoid/mongoid_spec_helper.rb +11 -0
  29. data/spec/spec_helper.rb +10 -67
  30. data/spec/support/activerecord/schema.rb +32 -0
  31. data/spec/{facteur_spec.rb → support/facteur_examples.rb} +38 -49
  32. data/spec/support/mongoid/database.rb +12 -0
  33. metadata +139 -20
  34. data/.document +0 -5
  35. data/VERSION +0 -1
  36. data/lib/facteur/rails/tasks/facteur.rake +0 -13
  37. data/lib/generators/facteur/install/templates/mailbox.rb +0 -3
  38. data/lib/generators/facteur/install/templates/message.rb +0 -3
data/Rakefile CHANGED
@@ -1,41 +1,19 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "facteur"
8
- gem.summary = "Messaging system for Rails 3"
9
- gem.description = "Facteur allows you add a messaging system in your Rails 3. You can create many mailboxes for your users. They will be able to send and receive messages."
10
- gem.email = "dev@raw1z.fr"
11
- gem.homepage = "http://github.com/raw1z/facteur"
12
- gem.authors = ["Rawane ZOSSOU"]
13
- gem.add_development_dependency "rspec", ">= 1.2.9"
14
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
- end
16
- Jeweler::GemcutterTasks.new
17
- rescue LoadError
18
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
- end
20
-
21
- require 'rspec/core'
22
- require 'rspec/core/rake_task'
23
- RSpec::Core::RakeTask.new(:spec) do |spec|
24
- end
25
-
26
- RSpec::Core::RakeTask.new(:rcov) do |spec|
27
- end
28
-
29
- task :spec => :check_dependencies
30
-
31
- task :default => :spec
32
-
33
- require 'rake/rdoctask'
34
- Rake::RDocTask.new do |rdoc|
35
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
36
-
37
- rdoc.rdoc_dir = 'rdoc'
38
- rdoc.title = "facteur #{version}"
39
- rdoc.rdoc_files.include('README*')
40
- rdoc.rdoc_files.include('lib/**/*.rb')
41
- end
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec'
5
+ require 'rspec/core/rake_task'
6
+
7
+ namespace :spec do
8
+ Rspec::Core::RakeTask.new(:activerecord) do |t|
9
+ t.pattern = "./spec/activerecord/**/*_spec.rb"
10
+ t.rspec_opts = "--format Fuubar"
11
+ end
12
+
13
+ Rspec::Core::RakeTask.new(:mongoid) do |t|
14
+ t.pattern = "./spec/mongoid/**/*_spec.rb"
15
+ t.rspec_opts = "--format Fuubar"
16
+ end
17
+ end
18
+
19
+
@@ -1,14 +1,25 @@
1
- require File.join(File.dirname(__FILE__), 'facteur/message_model')
2
- require File.join(File.dirname(__FILE__), 'facteur/mailbox_model')
3
- require File.join(File.dirname(__FILE__), 'facteur/addressee_model')
4
- require 'rails'
5
-
6
- module Facteur
7
- module Rails
8
- class Railtie < ::Rails::Railtie
9
- rake_tasks do
10
- load "facteur/rails/tasks/facteur.rake"
11
- end
12
- end
13
- end
14
- end
1
+ require 'active_support/concern'
2
+ require 'active_support/dependencies/autoload'
3
+
4
+ module Facteur
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :ActiveRecordMessageModel
8
+ autoload :MongoidMessageModel
9
+ autoload :MessageModel
10
+ autoload :ActiveRecordMailboxModel
11
+ autoload :MongoidMailboxModel
12
+ autoload :MailboxModel
13
+ autoload :BaseAddresseeModel
14
+ autoload :ActiveRecordAddresseeModel
15
+ autoload :MongoidAddresseeModel
16
+ autoload :AddresseeModel
17
+
18
+ def self.addressee_model
19
+ @addressee_model || "User"
20
+ end
21
+
22
+ def self.addressee_model=(model)
23
+ @addressee_model = model
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ require 'active_record'
2
+
3
+ module Facteur
4
+ module ActiveRecordAddresseeModel
5
+ include Facteur::BaseAddresseeModel
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :mailboxes, :as => :addressee, :class_name => "Facteur::Mailbox"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_record'
2
+
3
+ module Facteur
4
+ module ActiveRecordMailboxModel
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ belongs_to :addressee, :polymorphic => true
9
+ has_many :messages, :class_name => "Facteur::Message"
10
+
11
+ validates_presence_of :name
12
+ validates_uniqueness_of :name, :scope => [:addressee_id, :addressee_type]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ require 'active_record'
2
+
3
+ module Facteur
4
+ module ActiveRecordMessageModel
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ validates_presence_of :author_id, :mailbox_id, :body
9
+
10
+ belongs_to :mailbox,
11
+ :class_name => "Facteur::Mailbox"
12
+
13
+ belongs_to :author,
14
+ :class_name => Facteur.addressee_model,
15
+ :foreign_key => "author_id"
16
+
17
+ has_and_belongs_to_many :addressees,
18
+ :class_name => Facteur.addressee_model,
19
+ :join_table => "messages_addressees",
20
+ :association_foreign_key => "addressee_id"
21
+ end
22
+ end
23
+ end
24
+
@@ -1,145 +1,44 @@
1
1
  module Facteur
2
2
  module AddresseeModel
3
- def self.included(receiver)
4
- receiver.class_exec do
5
- include InstanceMethods
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ Facteur.addressee_model = self.to_s
7
+ Facteur.send(:remove_const, :Mailbox) if Facteur.const_defined?(:Mailbox)
8
+ Facteur.send(:remove_const, :Message) if Facteur.const_defined?(:Message)
9
+
10
+ if self.ancestors.map(&:to_s).include?("ActiveRecord::Base")
6
11
 
7
- has_many :mailboxes, :as => :addressee
8
- has_many :messages_sent, :class_name => "Message", :foreign_key => "author_id"
9
-
10
- # the addressee's mailboxes are created after its creation
11
- after_create :create_mailboxes
12
- end
13
-
14
- receiver.extend ClassMethods
15
- end
16
-
17
- module ClassMethods
18
-
19
- # Define a mailbox. The following options are available:
20
- # <tt>:default</tt>:: defines the default mailbox. You must choose one default mailbox
21
- def mailbox(name, options={})
22
- mailbox = {:name => name}
23
- mailbox.merge! options
24
- mailboxes << mailbox
25
- end
26
-
27
- # Returns the mailboxes defined for the class
28
- def mailboxes
29
- @mailboxes ||= []
30
- end
31
-
32
- def update_addressees_mailboxes
33
- all.each do |addressee|
34
- @mailboxes.each do |mailbox|
35
- options = {}.merge(mailbox)
36
- name = options.delete(:name)
37
- addressee.create_mailbox(name, options)
38
- end
12
+ Facteur.const_set(:Mailbox, Class.new(ActiveRecord::Base))
13
+ Facteur::Mailbox.class_exec do
14
+ include Facteur::ActiveRecordMailboxModel
39
15
  end
40
- end
41
- end
42
-
43
- module InstanceMethods
44
-
45
- # Sends a message to one or many addressees. The following options are available:
46
- #
47
- # <tt>:to</tt>:: the addressee or the list of addressees (mandatory)
48
- # <tt>:in</tt>:: the name of the mailbox in which the message is posted (mandatory)
49
- # <tt>:body</tt>:: the message's body (mandatory)
50
- #
51
- # Usage :
52
- #
53
- # # send a message to one addressee
54
- # @john.send_message('message contents', :to => @peter, :in => :private_mailbox)
55
- #
56
- # # send a message to many addressees
57
- # @john.send_message('message contents', :to => [@peter, @james], :in => :private_mailbox)
58
- def send_message(message, options)
59
- msg = nil
60
- options[:body] = message
61
- if options[:to].is_a? Array
62
- options[:to].each do |addressee|
63
- msg = send_message_to(addressee, options[:in], options[:body], options[:subject])
64
- end
65
- else
66
- msg = send_message_to(options[:to], options[:in], options[:body], options[:subject])
16
+
17
+ Facteur.const_set(:Message, Class.new(ActiveRecord::Base))
18
+ Facteur::Message.class_exec do
19
+ include Facteur::ActiveRecordMessageModel
67
20
  end
68
- msg
69
- end
70
-
71
- # Creates a new mailbox. if a mailbox with the same name already exists, it fails and returns false. If succeeded, it creates an accessor for the new mail box and returns true.
72
- # Example :
73
- #
74
- # class User < ActiveRecord::base
75
- # include Facteur::AddresseeModel
76
- #
77
- # mailbox :private_mailbox
78
- # end
79
- #
80
- # The previous declaration will add : User#private_mailbox
81
- #
82
- # # supposing that a name field exists
83
- # user = User.new(:name => 'John')
84
- # user.create_mailbox :public_mailbox #=> return true
85
- # user.create_mailbox :private_mailbox #=> return false
86
- def create_mailbox(name, options={})
87
- mailbox = Mailbox.new(:name => name.to_s)
88
- mailbox.addressee = self
89
- mailbox.default = options[:default]
90
- return false if mailbox.save == false
91
21
 
92
- @default_mailbox = name if options[:default]
93
- true
94
- end
95
-
96
- # Creates a new mailbox. if a mailbox with the same name already exists, it raises an exception. If succeeded, it creates an accessor for the new mail box and returns the created mailbox.
97
- def create_mailbox!(name, options={})
98
- if create_mailbox(name, options) == false
99
- raise "Mailboxes names must be unique. Can't create '#{name}'"
100
- end
101
- self.send "#{name}"
102
- end
22
+ include Facteur::ActiveRecordAddresseeModel
103
23
 
104
- # generates the mailboxes accessors
105
- def method_missing(method, *args, &block)
106
- super if method == :to_ary
24
+ elsif self.ancestors.map(&:to_s).include?("Mongoid::Document")
107
25
 
108
- begin
109
- super
110
- rescue NoMethodError
111
- mailbox = Mailbox.find(:first, :conditions => {:name => method.to_s, :addressee_id => self.attributes["id"], :addressee_type => self.class.to_s})
112
- return mailbox unless mailbox.nil?
113
- super
26
+ Facteur.const_set(:Mailbox, Class.new)
27
+ Facteur::Mailbox.class_exec do
28
+ include Mongoid::Document
29
+ include Facteur::MongoidMailboxModel
114
30
  end
115
-
116
- end
117
-
118
- private
119
-
120
- # creates the mailboxes defined in the configuration
121
- def create_mailboxes
122
- self.class.mailboxes.each do |mailbox|
123
- options = {}.merge(mailbox)
124
- name = options.delete(:name)
125
- create_mailbox!(name, options)
31
+
32
+ Facteur.const_set(:Message, Class.new)
33
+ Facteur::Message.class_exec do
34
+ include Mongoid::Document
35
+ include Facteur::MongoidMessageModel
126
36
  end
127
- end
128
-
129
- # send a message to an addressee
130
- def send_message_to(addressee, mailbox_name, contents, subject=nil)
131
- return false if addressee.nil? or contents.nil?
132
37
 
133
- mailbox_name = @default_mailbox if mailbox_name.nil?
134
- return false if mailbox_name.nil?
38
+ include Facteur::MongoidAddresseeModel
135
39
 
136
- message = Message.new
137
- message.author = self
138
- message.mailbox = addressee.send(mailbox_name)
139
- message.body = contents
140
- message.subject = subject
141
- message.save
142
- message
40
+ else
41
+ raise "Facteur only supports ActiveRecord and Mongoid"
143
42
  end
144
43
  end
145
44
  end
@@ -0,0 +1,163 @@
1
+ module Facteur
2
+ module BaseAddresseeModel
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ # Define a mailbox. The following options are available:
7
+ # <tt>:default</tt>:: defines the default mailbox. You must choose one default mailbox
8
+ def mailbox(name, options={})
9
+ mailbox = {:name => name}
10
+ mailbox.merge! options
11
+ mailboxes << mailbox
12
+ end
13
+
14
+ # Returns the mailboxes defined for the class
15
+ def mailboxes
16
+ @mailboxes ||= []
17
+ end
18
+
19
+ # check if a mailbox is defined
20
+ def has_mailbox?(name)
21
+ @mailboxes.each do |mailbox|
22
+ return true if mailbox[:name] == name
23
+ end
24
+ false
25
+ end
26
+
27
+ # return the default mailbox name if set, else return nil
28
+ def default_mailbox
29
+ @mailboxes.select{ |mailbox| mailbox[:default] == true }.first[:name]
30
+ end
31
+ end
32
+
33
+ module InstanceMethods
34
+ # returns the messages sent by this addressee
35
+ def sent_messages
36
+ sent_messages_mailbox.messages
37
+ end
38
+
39
+ # Sends a message to one or many addressees. The following options are available:
40
+ #
41
+ # <tt>:to</tt>:: the addressee or the list of addressees (mandatory)
42
+ # <tt>:in</tt>:: the name of the mailbox in which the message is posted (mandatory)
43
+ # <tt>:body</tt>:: the message's body (mandatory)
44
+ #
45
+ # Usage :
46
+ #
47
+ # # send a message to one addressee
48
+ # @john.send_message('message contents', :to => @peter, :in => :private_mailbox)
49
+ #
50
+ # # send a message to many addressees
51
+ # @john.send_message('message contents', :to => [@peter, @james], :in => :private_mailbox)
52
+ def send_message(message, options)
53
+ options[:body] = message
54
+ if options[:to].respond_to?(:each)
55
+ options[:to].each { |addressee| send_message_to(addressee, options[:in], options[:body], options[:subject]) }
56
+ else
57
+ send_message_to(options[:to], options[:in], options[:body], options[:subject])
58
+ end
59
+
60
+ store_in_sent_messages(message, options)
61
+ end
62
+
63
+ # Creates a new mailbox. if a mailbox with the same name already exists, it fails and returns false. If succeeded, it creates an accessor for the new mail box and returns true.
64
+ # Example :
65
+ #
66
+ # class User < ActiveRecord::base
67
+ # include Facteur::AddresseeModel
68
+ #
69
+ # mailbox :private_mailbox
70
+ # end
71
+ #
72
+ # The previous declaration will add : User#private_mailbox
73
+ #
74
+ # # supposing that a name field exists
75
+ # user = User.new(:name => 'John')
76
+ # user.create_mailbox :public_mailbox #=> return true
77
+ # user.create_mailbox :private_mailbox #=> return false
78
+ def create_mailbox(name, options={})
79
+ mailbox = mailboxes.build(:name => name.to_s, :default => options[:default])
80
+ return false if mailbox.save == false
81
+ mailbox
82
+ end
83
+
84
+ # Creates a new mailbox. if a mailbox with the same name already exists, it raises an exception. If succeeded, it creates an accessor for the new mail box and returns the created mailbox.
85
+ def create_mailbox!(name, options={})
86
+ if create_mailbox(name, options) == false
87
+ raise "Mailboxes names must be unique. Can't create '#{name}'"
88
+ end
89
+ self.send "#{name}"
90
+ end
91
+
92
+ # generates the mailboxes accessors
93
+ def method_missing(method, *args, &block)
94
+ begin
95
+ super
96
+ rescue NoMethodError, NameError
97
+ mailbox = self.mailboxes.where(:name => method.to_s).first
98
+ if mailbox.nil?
99
+ super unless self.class.has_mailbox?(method)
100
+
101
+ # if the unknown method matches one of the Model mailboxes, then the mailbox is created
102
+ create_mailbox(method, self.class.mailboxes.select{ |m| m[:name] == method }.first)
103
+ else
104
+ return mailbox
105
+ end
106
+ end
107
+ end
108
+
109
+ # redefine the comparison method because for some weirds reasons, the original fails
110
+ def ==(comparison_object)
111
+ comparison_object.equal?(self) ||
112
+ (self.class.to_s == comparison_object.class.to_s &&
113
+ comparison_object.id == id && !comparison_object.new_record?)
114
+ end
115
+
116
+ private
117
+
118
+ # return the sent messages mailbox
119
+ def sent_messages_mailbox
120
+ mailbox = self.mailboxes.where(:name => "sent_messages_mailbox").first
121
+ mailbox || create_mailbox("sent_messages_mailbox")
122
+ end
123
+
124
+ # creates the mailboxes defined in the configuration
125
+ def create_mailboxes
126
+ self.class.mailboxes.each do |mailbox|
127
+ options = {}.merge(mailbox)
128
+ name = options.delete(:name)
129
+ create_mailbox!(name, options)
130
+ end
131
+ end
132
+
133
+ # send a message to an addressee
134
+ def send_message_to(addressee, mailbox_name, contents, subject=nil)
135
+ return false if addressee.nil? or contents.nil?
136
+
137
+ mailbox_name = self.class.default_mailbox if mailbox_name.nil?
138
+ return false if mailbox_name.nil?
139
+
140
+ message = addressee.send(mailbox_name).messages.build(:subject => subject, :body => contents)
141
+ message.author = self
142
+ message.save ? message : false
143
+ end
144
+
145
+ # saves a message in the sent messages mailbox
146
+ def store_in_sent_messages(message, options)
147
+ # the addressees must be given
148
+ return false if options[:to].blank?
149
+
150
+ sent_message = sent_messages_mailbox.messages.build(:subject => options[:subject], :body => options[:body])
151
+ sent_message.author = self
152
+
153
+ if options[:to].respond_to?(:each)
154
+ options[:to].each { |addressee| sent_message.addressees << addressee }
155
+ else
156
+ sent_message.addressees << options[:to]
157
+ end
158
+
159
+ sent_message.save ? sent_message : false
160
+ end
161
+ end
162
+ end
163
+ end