markbates-blabber_mouth 0.1.0.20090714164111
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README +29 -0
- data/lib/blabber_mouth.rb +28 -0
- data/lib/blabber_mouth/adapters/base.rb +30 -0
- data/lib/blabber_mouth/adapters/tmail.rb +77 -0
- data/lib/blabber_mouth/adapters/xmpp_msg.rb +59 -0
- data/lib/blabber_mouth/attachment.rb +29 -0
- data/lib/blabber_mouth/blabber_mouth.rb +181 -0
- data/lib/blabber_mouth/delivery_handlers/sendmail.rb +19 -0
- data/lib/blabber_mouth/delivery_handlers/smtp.rb +18 -0
- data/lib/blabber_mouth/delivery_handlers/test.rb +15 -0
- data/lib/blabber_mouth/delivery_handlers/xmpp_transport.rb +76 -0
- data/lib/blabber_mouth/errors.rb +55 -0
- data/lib/blabber_mouth/loader.rb +8 -0
- data/lib/blabber_mouth/notifier_generator/manifest.yml +12 -0
- data/lib/blabber_mouth/notifier_generator/notifier_generator.rb +23 -0
- data/lib/blabber_mouth/notifier_generator/templates/app/notifiers/html.erb.template +2 -0
- data/lib/blabber_mouth/notifier_generator/templates/app/notifiers/notifier.rb.template +3 -0
- data/lib/blabber_mouth/notifier_generator/templates/app/notifiers/plain.erb.template +2 -0
- data/lib/blabber_mouth/rendering/type/mailer.rb +14 -0
- data/lib/blabber_mouth/settings.rb +28 -0
- data/lib/blabber_mouth/testing.rb +47 -0
- data/lib/blabber_mouth/utils/registry_list.rb +82 -0
- data/lib/blabber_mouth/validations.rb +97 -0
- metadata +116 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 markbates
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
This gem provides a simple API for creating emails within a Mack application.
|
2
|
+
|
3
|
+
A simple BlabberMouth model would look like this:
|
4
|
+
|
5
|
+
class WelcomeEmail
|
6
|
+
include BlabberMouth
|
7
|
+
end
|
8
|
+
|
9
|
+
To use this in your application you would do something like the following:
|
10
|
+
|
11
|
+
mail = WelcomeEmail.new
|
12
|
+
mail.to = "foo@example.com"
|
13
|
+
mail.from = "me@example.com"
|
14
|
+
mail.subject = "Hello"
|
15
|
+
mail.body(:plain, "This is my plain text body")
|
16
|
+
mail.body(:html, "This is my <b>HTML</b> body")
|
17
|
+
mail.attach(BlabberMouth::Attachment.new("/path/to/my/image_file.png"))
|
18
|
+
mail.attach(BlabberMouth::Attachment.new("/path/to/my/pdf_file.pdf"))
|
19
|
+
mail.deliver
|
20
|
+
|
21
|
+
This gem currently has an adapter for TMail, but it can support any mailing
|
22
|
+
framework under the covers with the creation of a simple adapter class.
|
23
|
+
|
24
|
+
Currently implemented delivery handlers are: SMTP (default), sendmail, and test.
|
25
|
+
|
26
|
+
== Testing
|
27
|
+
|
28
|
+
When testing you can get access to delivered emails with the delivered_notifiers
|
29
|
+
method. After each tests these emails will be flushed our of the test handler.
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'configatron'
|
2
|
+
require 'genosaurus'
|
3
|
+
require 'validatable'
|
4
|
+
require 'tmail'
|
5
|
+
require 'xmpp4r'
|
6
|
+
require 'xmpp4r-simple'
|
7
|
+
require 'activesupport'
|
8
|
+
|
9
|
+
fl = File.join(File.dirname(__FILE__), "blabber_mouth")
|
10
|
+
|
11
|
+
require File.join(fl, "settings")
|
12
|
+
require File.join(fl, "errors")
|
13
|
+
require File.join(fl, "attachment")
|
14
|
+
require File.join(fl, "notifier_generator", "notifier_generator")
|
15
|
+
|
16
|
+
[:utils, :delivery_handlers, :adapters, :rendering].each do |dir|
|
17
|
+
Dir.glob(File.join(fl, dir.to_s, "**/*.rb")).each do |h|
|
18
|
+
require h
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require File.join(fl, "blabber_mouth")
|
23
|
+
|
24
|
+
require File.join(fl, "validations")
|
25
|
+
|
26
|
+
require File.join(fl, "testing")
|
27
|
+
|
28
|
+
require File.join(fl, "loader")
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module BlabberMouth
|
2
|
+
module Adapters # :nodoc:
|
3
|
+
# All mail adapters need to extend this class.
|
4
|
+
class Base
|
5
|
+
|
6
|
+
# The origina BlabberMouth object passed in.
|
7
|
+
attr_accessor :bm_notifier
|
8
|
+
|
9
|
+
def initialize(mail) # :nodoc:
|
10
|
+
self.bm_notifier = mail
|
11
|
+
end
|
12
|
+
|
13
|
+
# The transformed (ie, converted, object)
|
14
|
+
def transformed(*args)
|
15
|
+
raise NoMethodError.new('transformed')
|
16
|
+
end
|
17
|
+
|
18
|
+
# Convert the BlabberMouth object to the adapted object.
|
19
|
+
def convert(*args)
|
20
|
+
raise NoMethodError.new('convert')
|
21
|
+
end
|
22
|
+
|
23
|
+
# The RAW encoded String ready for delivery via SMTP, Sendmail, etc...
|
24
|
+
def deliverable(*args)
|
25
|
+
raise NoMethodError.new('deliverable')
|
26
|
+
end
|
27
|
+
|
28
|
+
end # Base
|
29
|
+
end # Adapters
|
30
|
+
end # BlabberMouth
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "base")
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module BlabberMouth
|
5
|
+
module Adapters # :nodoc:
|
6
|
+
# Converts a BlabberMouth object into a TMail object.
|
7
|
+
class Tmail < BlabberMouth::Adapters::Base
|
8
|
+
|
9
|
+
# Returns the underlying TMail object.
|
10
|
+
# Raises BlabberMouth::Errors::UnconvertedNotifier if the convert method hasn't
|
11
|
+
# been called first.
|
12
|
+
def transformed
|
13
|
+
raise BlabberMouth::Errors::UnconvertedNotifier.new if @tmail.nil?
|
14
|
+
@tmail
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the ready to be delivered encoded String
|
18
|
+
def deliverable
|
19
|
+
transformed.encoded
|
20
|
+
end
|
21
|
+
|
22
|
+
# Converts the BlabberMouth object to a TMail object.
|
23
|
+
def convert
|
24
|
+
@tmail = TMail::Mail.new
|
25
|
+
@tmail.to = bm_notifier.to
|
26
|
+
@tmail.cc = bm_notifier.cc
|
27
|
+
@tmail.bcc = bm_notifier.bcc
|
28
|
+
@tmail.reply_to = bm_notifier.reply_to
|
29
|
+
@tmail.from = bm_notifier.from
|
30
|
+
@tmail.subject = bm_notifier.subject
|
31
|
+
@tmail.date = bm_notifier.date_sent
|
32
|
+
@tmail.mime_version = bm_notifier.mime_version
|
33
|
+
|
34
|
+
# set text and html bodies
|
35
|
+
main_body = TMail::Mail.new
|
36
|
+
unless bm_notifier.body(:plain).blank?
|
37
|
+
text = TMail::Mail.new
|
38
|
+
text.content_type = "text/plain"
|
39
|
+
text.body = bm_notifier.body(:plain)
|
40
|
+
main_body.parts << text
|
41
|
+
end
|
42
|
+
unless bm_notifier.body(:html).blank?
|
43
|
+
html = TMail::Mail.new
|
44
|
+
html.content_type = "text/html"
|
45
|
+
html.body = bm_notifier.body(:html)
|
46
|
+
main_body.parts << html
|
47
|
+
end
|
48
|
+
|
49
|
+
unless main_body.parts.empty?
|
50
|
+
main_body.content_type = "multipart/alternative"
|
51
|
+
if bm_notifier.attachments.any? # there's an attachment
|
52
|
+
@tmail.parts << main_body
|
53
|
+
else
|
54
|
+
if main_body.parts.size == 1
|
55
|
+
@tmail.body = main_body.parts.first.body
|
56
|
+
else
|
57
|
+
@tmail.parts << main_body
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# set attachments, if any.
|
63
|
+
bm_notifier.attachments.each do |at|
|
64
|
+
attachment = TMail::Mail.new
|
65
|
+
attachment.body = Base64.encode64(at.body)
|
66
|
+
attachment.transfer_encoding = "Base64"
|
67
|
+
attachment.content_type = "application/octet-stream"
|
68
|
+
attachment['Content-Disposition'] = "attachment; filename=#{at.file_name}"
|
69
|
+
@tmail.parts << attachment
|
70
|
+
end
|
71
|
+
|
72
|
+
@tmail.content_type = bm_notifier.content_type
|
73
|
+
end
|
74
|
+
|
75
|
+
end # Tmail
|
76
|
+
end # Adapters
|
77
|
+
end # BlabberMouth
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module BlabberMouth
|
2
|
+
module Adapters # :nodoc:
|
3
|
+
|
4
|
+
class XmppMsgContainer
|
5
|
+
attr_accessor :messages
|
6
|
+
attr_accessor :recipients
|
7
|
+
def initialize
|
8
|
+
self.messages = []
|
9
|
+
self.recipients = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_message_by_recipient(rcpt)
|
13
|
+
self.messages.find { |x| x.to.to_s == rcpt.to_s }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# All mail adapters need to extend this class.
|
19
|
+
class Xmpp < BlabberMouth::Adapters::Base
|
20
|
+
include Jabber
|
21
|
+
|
22
|
+
# The transformed (ie, converted, object)
|
23
|
+
def transformed
|
24
|
+
raise BlabberMouth::Errors::UnconvertedNotifier.new if @xmpp_msg.nil?
|
25
|
+
return @xmpp_container
|
26
|
+
end
|
27
|
+
|
28
|
+
# Convert the BlabberMouth object to the adapted object.
|
29
|
+
def convert
|
30
|
+
settings = configatron.blabber_mouth.xmpp_settings
|
31
|
+
arr = [bm_notifier.to].flatten
|
32
|
+
@xmpp_container = XmppMsgContainer.new
|
33
|
+
@xmpp_container.recipients = arr
|
34
|
+
|
35
|
+
arr.each do |rcpt|
|
36
|
+
xmpp_msg = Message::new
|
37
|
+
xmpp_msg.set_type(:normal)
|
38
|
+
xmpp_msg.set_to(rcpt)
|
39
|
+
xmpp_msg.set_from(bm_notifier.from)
|
40
|
+
xmpp_msg.set_subject(bm_notifier.subject)
|
41
|
+
xmpp_msg.set_type(settings.message_type)
|
42
|
+
unless bm_notifier.body(:plain).blank?
|
43
|
+
xmpp_msg.set_body(bm_notifier.body(:plain))
|
44
|
+
end
|
45
|
+
|
46
|
+
@xmpp_container.messages << xmpp_msg
|
47
|
+
end
|
48
|
+
|
49
|
+
return @xmpp_container
|
50
|
+
end
|
51
|
+
|
52
|
+
# The RAW encoded String ready for delivery via SMTP, Sendmail, etc...
|
53
|
+
def deliverable
|
54
|
+
return @xmpp_container
|
55
|
+
end
|
56
|
+
|
57
|
+
end # Base
|
58
|
+
end # Adapters
|
59
|
+
end # BlabberMouth
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module BlabberMouth
|
2
|
+
# Creates an attachment for a BlabberMouth object.
|
3
|
+
class Attachment
|
4
|
+
|
5
|
+
# Returns a String representing the body of the attachment. This String is NOT encoded in anyway!
|
6
|
+
attr_accessor :body
|
7
|
+
# Returns the name of the attached file.
|
8
|
+
attr_accessor :file_name
|
9
|
+
|
10
|
+
def initialize(body = nil)
|
11
|
+
unless body.nil?
|
12
|
+
self.add_file(body) if body.is_a?(String)
|
13
|
+
self.add_io(body) if body.is_a?(IO)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Takes an IO object and sets the body. You'll need to explicity set the file_name afterwards.
|
18
|
+
def add_io(io)
|
19
|
+
self.body = io.read
|
20
|
+
end
|
21
|
+
|
22
|
+
# Takes a path to a file, reads it in, and sets the file_name based on the path.
|
23
|
+
def add_file(file)
|
24
|
+
self.file_name = File.basename(file)
|
25
|
+
self.body = File.read(file)
|
26
|
+
end
|
27
|
+
|
28
|
+
end # Attachment
|
29
|
+
end # BlabberMouth
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# The heart and soul of the mack-notifier package.
|
2
|
+
module BlabberMouth
|
3
|
+
|
4
|
+
attr_accessor :to
|
5
|
+
attr_accessor :cc
|
6
|
+
attr_accessor :bcc
|
7
|
+
attr_accessor :from
|
8
|
+
attr_accessor :reply_to
|
9
|
+
attr_accessor :subject
|
10
|
+
attr_accessor :date_sent
|
11
|
+
attr_accessor :mime_version
|
12
|
+
attr_accessor :content_type
|
13
|
+
|
14
|
+
# A helper method that takes a Hash and will populate the notification with the key/value pairs of that Hash.
|
15
|
+
# Use body_* to set a body part.
|
16
|
+
def build(options = {})
|
17
|
+
options.each do |k,v|
|
18
|
+
k = k.to_s
|
19
|
+
unless k.match(/^body_/)
|
20
|
+
self.send("#{k}=", v)
|
21
|
+
else
|
22
|
+
k.gsub!("body_", "")
|
23
|
+
self.body(k, v)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# If called with two parameters it will set the value of the body type to the second parameter.
|
29
|
+
#
|
30
|
+
# Example:
|
31
|
+
# body(:plain, "hello") # => sets the 'plain' body to "hello"
|
32
|
+
#
|
33
|
+
# If called with just one parameter it will return the value of that body type. If the value is nil
|
34
|
+
# the template for that body type will be rendered.
|
35
|
+
#
|
36
|
+
# Example:
|
37
|
+
# body(:plain) # => "hello"
|
38
|
+
# body(:html) # => will call the html.erb template for this notifier.
|
39
|
+
def body(part, value = nil)
|
40
|
+
part = part.to_sym
|
41
|
+
if value.nil?
|
42
|
+
body = bodies[part]
|
43
|
+
if body.blank?
|
44
|
+
bodies[part] = build_template(part)
|
45
|
+
return bodies[part]
|
46
|
+
else
|
47
|
+
return body
|
48
|
+
end
|
49
|
+
else
|
50
|
+
bodies[part] = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the mime_version of the notification, defaults to "1.0"
|
55
|
+
def mime_version
|
56
|
+
(@mime_version ||= "1.0")
|
57
|
+
end
|
58
|
+
|
59
|
+
# This will attempt to determine the content type of the notification, unless one is already specified.
|
60
|
+
def content_type
|
61
|
+
return @content_type unless @content_type.blank?
|
62
|
+
if has_attachments?
|
63
|
+
return "multipart/mixed"
|
64
|
+
elsif !body(:plain).blank? && !body(:html).blank?
|
65
|
+
return "multipart/alternative"
|
66
|
+
elsif body(:html)
|
67
|
+
return "text/html"
|
68
|
+
else
|
69
|
+
return "text/plain"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the date sent, defaults to Time.now
|
74
|
+
def date_sent
|
75
|
+
(@date_sent ||= Time.now)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns the reply to address, defaults to the from address.
|
79
|
+
def reply_to
|
80
|
+
(@reply_to || self.from)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Adds a BlabberMouth::Attachment to the notifier.
|
84
|
+
# Raise ArgumentError if the parameter is not a BlabberMouth::Attachment
|
85
|
+
def attach(file)
|
86
|
+
raise ArgumentError.new unless file.is_a?(BlabberMouth::Attachment)
|
87
|
+
attachments << file
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns true if there are attachments.
|
91
|
+
def has_attachments?
|
92
|
+
!attachments.empty?
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the attachments Array.
|
96
|
+
def attachments
|
97
|
+
@attachments ||= []
|
98
|
+
end
|
99
|
+
|
100
|
+
# Delivers the notification with the configured BlabberMouth::DeliveryHandlers class.
|
101
|
+
# Returns false if there are any errors.
|
102
|
+
def deliver(handler = deliver_with)
|
103
|
+
begin
|
104
|
+
deliver!(handler)
|
105
|
+
rescue Exception => e
|
106
|
+
return false
|
107
|
+
end
|
108
|
+
return true
|
109
|
+
end
|
110
|
+
|
111
|
+
# Delivers the email with the configured BlabberMouth::DeliveryHandlers class.
|
112
|
+
def deliver!(handler = deliver_with)
|
113
|
+
"BlabberMouth::DeliveryHandlers::#{handler.to_s.camelcase}".constantize.deliver(self)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns all the recipients of this notifier.
|
117
|
+
def recipients
|
118
|
+
[self.to, self.cc, self.bcc].flatten.compact
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns a ready to be delivered, encoded, version of the notification.
|
122
|
+
def deliverable(adap = adapter)
|
123
|
+
adap = "BlabberMouth::Adapters::#{adap.to_s.camelcase}".constantize.new(self)
|
124
|
+
adap.convert
|
125
|
+
adap.deliverable
|
126
|
+
end
|
127
|
+
|
128
|
+
# This method returns the adapter that will transform the BlabberMouth object
|
129
|
+
# and prepare it for delivery. This method returns the configatron.notifier.adapter
|
130
|
+
# parameter. Override this in your BlabberMouth class to specify a different adapter
|
131
|
+
# or change the configatron parameter to globally affect all your Notifiers.
|
132
|
+
#
|
133
|
+
# Default: :tmail
|
134
|
+
def adapter
|
135
|
+
configatron.blabber_mouth.adapter
|
136
|
+
end
|
137
|
+
|
138
|
+
# This method returns the delivery handler that will delivers the BlabberMouth object.
|
139
|
+
# This method returns the configatron.blabber_mouth.deliver_with parameter. Override this in
|
140
|
+
# your BlabberMouth class to specify a different handler or change the configatron
|
141
|
+
# parameter to globally affect all your Notifiers.
|
142
|
+
#
|
143
|
+
# Default: :sendmail
|
144
|
+
def deliver_with
|
145
|
+
configatron.blabber_mouth.deliver_with
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
def bodies
|
150
|
+
@bodies ||= {}
|
151
|
+
end
|
152
|
+
|
153
|
+
def build_template(format)
|
154
|
+
path = File.join(configatron.blabber_mouth.paths.templates, self.class.to_s.underscore, "#{format}.erb")
|
155
|
+
if File.exists?(path)
|
156
|
+
template = ERB.new(File.read(path))
|
157
|
+
return template.result(Template.new(self).binder)
|
158
|
+
end
|
159
|
+
# begin
|
160
|
+
# vt = BlabberMouth::Rendering::ViewTemplate.new(:notifier, self.class.to_s.underscore, {:locals => {:notifier => self}, :format => format.to_s})
|
161
|
+
# return vt._compile_and_render
|
162
|
+
# rescue BlabberMouth::Errors::ResourceNotFound => e
|
163
|
+
# end
|
164
|
+
return nil
|
165
|
+
end
|
166
|
+
|
167
|
+
class Template
|
168
|
+
|
169
|
+
attr_accessor :notifier
|
170
|
+
|
171
|
+
def initialize(notifier)
|
172
|
+
self.notifier = notifier
|
173
|
+
end
|
174
|
+
|
175
|
+
def binder
|
176
|
+
binding
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
end # BlabberMouth
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module BlabberMouth
|
2
|
+
module DeliveryHandlers # :nodoc:
|
3
|
+
# Delivers BlabberMouth objects using sendmail.
|
4
|
+
module Sendmail
|
5
|
+
|
6
|
+
def self.deliver(mail)
|
7
|
+
sendmail_settings = configatron.blabber_mouth.sendmail
|
8
|
+
sendmail_args = sendmail_settings.arguments
|
9
|
+
sendmail_args += " -f \"#{mail.reply_to}\"" if mail.reply_to
|
10
|
+
IO.popen("#{sendmail_settings.location} #{sendmail_args}","w+") do |sm|
|
11
|
+
sm.print(mail.deliverable.gsub(/\r/, ''))
|
12
|
+
sm.flush
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end # Sendmail
|
17
|
+
|
18
|
+
end # DeliveryHandlers
|
19
|
+
end # BlabberMouth
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
module BlabberMouth
|
3
|
+
module DeliveryHandlers # :nodoc:
|
4
|
+
# Delivers BlabberMouth objects using Net::SMTP.
|
5
|
+
module Smtp
|
6
|
+
|
7
|
+
def self.deliver(mail)
|
8
|
+
smtp_settings = configatron.blabber_mouth.smtp
|
9
|
+
Net::SMTP.start(smtp_settings.address, smtp_settings.port,
|
10
|
+
smtp_settings.domain, smtp_settings.retrieve(:user_name, nil),
|
11
|
+
smtp_settings.retrieve(:password, nil), smtp_settings.retrieve(:authentication, nil)) do |smtp|
|
12
|
+
smtp.sendmail(mail.deliverable, mail.reply_to, mail.recipients)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end # Smtp
|
17
|
+
end # DeliveryHandlers
|
18
|
+
end # BlabberMouth
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module BlabberMouth
|
2
|
+
module DeliveryHandlers # :nodoc:
|
3
|
+
# Delivers BlabberMouth objects to an Array.
|
4
|
+
module Test
|
5
|
+
|
6
|
+
def self.deliver(notifier)
|
7
|
+
NotifierRegistry.add(notifier)
|
8
|
+
end
|
9
|
+
|
10
|
+
class NotifierRegistry < BlabberMouth::Utils::RegistryList # :nodoc:
|
11
|
+
end
|
12
|
+
|
13
|
+
end # Test
|
14
|
+
end # DeliveryHandlers
|
15
|
+
end # BlabberMouth
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module BlabberMouth
|
2
|
+
module DeliveryHandlers # :nodoc:
|
3
|
+
# Delivers BlabberMouth objects using XMPP (Jabber)
|
4
|
+
module XmppTransport
|
5
|
+
|
6
|
+
def self.check_availability(client, recipients)
|
7
|
+
buddies = {}
|
8
|
+
recipients.each do |rcpt|
|
9
|
+
buddies[rcpt] = :offline
|
10
|
+
end
|
11
|
+
|
12
|
+
# try to get the presence update
|
13
|
+
sleep(1)
|
14
|
+
client.presence_updates do |update|
|
15
|
+
from = update[0].to_s
|
16
|
+
presence = update[1].to_s
|
17
|
+
if buddies.has_key?(from)
|
18
|
+
buddies[from] = presence
|
19
|
+
end
|
20
|
+
Mack.logger.info "#{from} --> #{presence}"
|
21
|
+
end
|
22
|
+
return buddies
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.deliver_message(client, xmpp_msg, wait_for_response, xmpp_errors)
|
26
|
+
Mack.logger.info "#{xmpp_msg.to} is online, delivering message"
|
27
|
+
client.deliver(xmpp_msg.to, xmpp_msg)
|
28
|
+
loop do
|
29
|
+
client.received_messages { |ret_msg| @msg_received = true if ret_msg.body == "ack" }
|
30
|
+
break if @msg_received or @error
|
31
|
+
end if wait_for_response
|
32
|
+
return xmpp_errors
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.deliver(xmpp_msg)
|
36
|
+
@ex ||= BlabberMouth::Errors::XmppError.new("xmpp error")
|
37
|
+
xmpp_settings = configatron.blabber_mouth.xmpp
|
38
|
+
jid_str = xmpp_settings.jid
|
39
|
+
jid_str += ("/" + xmpp_settings.jid_resource) if !jid_str.index("/")
|
40
|
+
password = xmpp_settings.password
|
41
|
+
client = Jabber::Simple.new(jid_str, password)
|
42
|
+
thr = Thread.new {
|
43
|
+
begin
|
44
|
+
xmpp_msg = xmpp_msg.deliverable
|
45
|
+
Timeout::timeout(20) do
|
46
|
+
buddies = check_availability(client, xmpp_msg.recipients)
|
47
|
+
|
48
|
+
online_buddies = buddies.keys.reject { |x| buddies[x].to_sym == :offline }
|
49
|
+
offline_buddies = buddies.keys.reject { |x| buddies[x].to_sym == :online }
|
50
|
+
|
51
|
+
if !offline_buddies.empty?
|
52
|
+
# there are offline buddies, log the errors
|
53
|
+
offline_buddies.each do |buddy|
|
54
|
+
err = BlabberMouth::Errors::XmppUserNotOnline.new(buddy)
|
55
|
+
@ex.add_error(:offline, err)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
online_buddies.each do |buddy|
|
60
|
+
deliver_message(client, xmpp_msg.find_message_by_recipient(buddy), xmpp_settings.wait_for_response, @ex)
|
61
|
+
end
|
62
|
+
|
63
|
+
raise @ex if !@ex.empty?
|
64
|
+
end # timeout
|
65
|
+
rescue Timeout::Error => ex
|
66
|
+
@error = ex
|
67
|
+
rescue Exception => ex
|
68
|
+
end
|
69
|
+
}
|
70
|
+
|
71
|
+
thr.join
|
72
|
+
raise @ex if !@ex.empty?
|
73
|
+
end
|
74
|
+
end # XmppTransport
|
75
|
+
end # DeliveryHandlers
|
76
|
+
end # BlabberMouth
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module BlabberMouth
|
2
|
+
module Errors # :nodoc:
|
3
|
+
|
4
|
+
class UnconvertedNotifier < StandardError
|
5
|
+
def initialize # :nodoc:
|
6
|
+
super("You must convert the BlabberMouth object first!")
|
7
|
+
end
|
8
|
+
end # UnconvertedNotifier
|
9
|
+
|
10
|
+
class XmppError < StandardError
|
11
|
+
def initialize(msg)
|
12
|
+
super(msg)
|
13
|
+
self.error_hash = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_error(type, msg)
|
17
|
+
self.error_hash[type] ||= []
|
18
|
+
self.error_hash[type] << msg
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_error(type)
|
22
|
+
self.error_hash[type]
|
23
|
+
end
|
24
|
+
|
25
|
+
def empty?
|
26
|
+
self.error_hash.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor :error_hash
|
30
|
+
end
|
31
|
+
|
32
|
+
class XmppAuthenticationError < StandardError
|
33
|
+
def initialize(user)
|
34
|
+
super("Cannot authenticate: #{user} to xmpp server")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class XmppUserNotOnline < StandardError
|
39
|
+
def initialize(user)
|
40
|
+
super("user #{user} is not online")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class XmppSendError < StandardError
|
45
|
+
attr_reader :code
|
46
|
+
attr_reader :msg
|
47
|
+
|
48
|
+
def initialize(code, msg)
|
49
|
+
super("Cannot send message. Code=#{code}, Msg=#{msg}")
|
50
|
+
@code = code
|
51
|
+
@msg = msg
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end # Errors
|
55
|
+
end # BlabberMouth
|
@@ -0,0 +1,12 @@
|
|
1
|
+
notifier_template:
|
2
|
+
type: file
|
3
|
+
template_path: <%= File.join(templates_directory_path, "app", "notifiers", "notifier.rb.template") %>
|
4
|
+
output_path: <%= File.join(configatron.blabber_mouth.paths.models, "#{file_name}.rb") %>
|
5
|
+
text_template:
|
6
|
+
type: file
|
7
|
+
template_path: <%= File.join(templates_directory_path, "app", "notifiers", "plain.erb.template") %>
|
8
|
+
output_path: <%= File.join(configatron.blabber_mouth.paths.templates, file_name, "plain.erb") %>
|
9
|
+
html_template:
|
10
|
+
type: file
|
11
|
+
template_path: <%= File.join(templates_directory_path, "app", "notifiers", "html.erb.template") %>
|
12
|
+
output_path: <%= File.join(configatron.blabber_mouth.paths.templates, file_name, "html.erb") %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Generates the necessary files for a basic notifier.
|
2
|
+
#
|
3
|
+
# Example:
|
4
|
+
# rake generate:notifier name=welcome_email
|
5
|
+
# generates the following files:
|
6
|
+
# app/notifiers/welcome_email.rb
|
7
|
+
# app/notifiers/templates/welcome_email/text.erb
|
8
|
+
# app/notifiers/templates/welcome_email/html.erb
|
9
|
+
# test/unit/welcome_email_spec.rb # => if using RSpec
|
10
|
+
# test/unit/welcome_email_test.rb # => if using Test::Unit::TestCase
|
11
|
+
class NotifierGenerator < Genosaurus
|
12
|
+
|
13
|
+
require_param :name
|
14
|
+
|
15
|
+
def file_name # :nodoc:
|
16
|
+
param(:name).underscore.downcase
|
17
|
+
end
|
18
|
+
|
19
|
+
def class_name # :nodoc:
|
20
|
+
param(:name).camelcase
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# module Rendering # :nodoc:
|
2
|
+
# module Type # :nodoc:
|
3
|
+
# class Notifier < BlabberMouth::Rendering::Type::FileBase # :nodoc:
|
4
|
+
#
|
5
|
+
# def render
|
6
|
+
# x_file = BlabberMouth::Paths.notifier_templates(self._render_value, self._options[:format])
|
7
|
+
# render_file(x_file)
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# end # BlabberMouth
|
11
|
+
# end # Type
|
12
|
+
# end # Rendering
|
13
|
+
#
|
14
|
+
# BlabberMouth::Rendering::Engine::Registry.instance.register(:notifier, :erb)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
if defined?(RAILS_ENV)
|
2
|
+
configatron.blabber_mouth.set_default(:env, RAILS_ENV)
|
3
|
+
configatron.blabber_mouth.paths.set_default(:models, File.join(RAILS_ROOT, 'app', 'notifiers'))
|
4
|
+
configatron.blabber_mouth.paths.set_default(:templates, File.join(RAILS_ROOT, 'app', 'notifiers', 'templates'))
|
5
|
+
else
|
6
|
+
configatron.blabber_mouth.set_default(:env, 'development')
|
7
|
+
configatron.blabber_mouth.paths.set_default(:models, File.join(FileUtils.pwd, 'app', 'notifiers'))
|
8
|
+
configatron.blabber_mouth.paths.set_default(:templates, File.join(FileUtils.pwd, 'app', 'notifiers', 'templates'))
|
9
|
+
end
|
10
|
+
|
11
|
+
configatron.blabber_mouth.paths.set_default(:templates, File.join(configatron.blabber_mouth.paths.models, 'templates'))
|
12
|
+
|
13
|
+
configatron.blabber_mouth.sendmail.set_default(:location, '/usr/sbin/sendmail')
|
14
|
+
configatron.blabber_mouth.sendmail.set_default(:arguments, '-i -t')
|
15
|
+
configatron.blabber_mouth.smtp.set_default(:address, 'localhost')
|
16
|
+
configatron.blabber_mouth.smtp.set_default(:port, 25)
|
17
|
+
configatron.blabber_mouth.smtp.set_default(:domain, 'localhost.localdomain')
|
18
|
+
configatron.blabber_mouth.set_default(:deliver_with, (configatron.blabber_mouth.env == "test" ? "test" : "smtp"))
|
19
|
+
configatron.blabber_mouth.set_default(:adapter, 'tmail')
|
20
|
+
|
21
|
+
# xmpp settings
|
22
|
+
configatron.blabber_mouth.xmpp.set_default(:jid, 'h_test@jabber80.com')
|
23
|
+
configatron.blabber_mouth.xmpp.set_default(:jid_resource, 'work')
|
24
|
+
configatron.blabber_mouth.xmpp.set_default(:password, 'test1234')
|
25
|
+
configatron.blabber_mouth.xmpp.set_default(:message_type, :chat)
|
26
|
+
configatron.blabber_mouth.xmpp.set_default(:wait_for_response, true)
|
27
|
+
configatron.blabber_mouth.xmpp.set_default(:response_wait_time, 20)
|
28
|
+
configatron.blabber_mouth.xmpp.set_default(:response_message, "ack")
|
@@ -0,0 +1,47 @@
|
|
1
|
+
if configatron.blabber_mouth.env == "test"
|
2
|
+
|
3
|
+
# Used for testing this method will return any emails that have been 'sent' using BlabberMouth::DeliveryHandlers::Test.
|
4
|
+
# These emails will get 'flushed' after each test.
|
5
|
+
def delivered_notifiers
|
6
|
+
BlabberMouth::DeliveryHandlers::Test::NotifierRegistry.registered_items
|
7
|
+
end
|
8
|
+
|
9
|
+
if defined?(Spec)
|
10
|
+
|
11
|
+
Spec::Runner.configure do |config|
|
12
|
+
|
13
|
+
config.before(:each) do
|
14
|
+
BlabberMouth::DeliveryHandlers::Test::NotifierRegistry.reset!
|
15
|
+
end
|
16
|
+
|
17
|
+
config.after(:each) do
|
18
|
+
BlabberMouth::DeliveryHandlers::Test::NotifierRegistry.reset!
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
else
|
24
|
+
|
25
|
+
module Test # :nodoc:
|
26
|
+
module Unit # :nodoc:
|
27
|
+
class TestCase # :nodoc:
|
28
|
+
|
29
|
+
# Let's alias the run method in the class above us so we can create a new one here
|
30
|
+
# but still reference it.
|
31
|
+
alias_instance_method :run, :super_run
|
32
|
+
|
33
|
+
# We need to wrap the run method so we can do things like
|
34
|
+
# run a cleanup method if it exists
|
35
|
+
def run(result, &progress_block) # :nodoc:
|
36
|
+
@__res = super_run(result)
|
37
|
+
BlabberMouth::DeliveryHandlers::Test::NotifierRegistry.reset!
|
38
|
+
@__res
|
39
|
+
end
|
40
|
+
|
41
|
+
end # TestCase
|
42
|
+
end # Unit
|
43
|
+
end # Test
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
module BlabberMouth
|
3
|
+
module Utils
|
4
|
+
# This is a general purpose Singleton Registry class.
|
5
|
+
# It takes the drudgery out of creating registry classes, that
|
6
|
+
# are, let's face it, all pretty much the same.
|
7
|
+
class RegistryList
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
# The list of registered items
|
11
|
+
attr_reader :registered_items
|
12
|
+
|
13
|
+
def initialize # :nodoc:
|
14
|
+
reset!
|
15
|
+
end
|
16
|
+
|
17
|
+
# Override this method to set the initial state of the registered_items Array.
|
18
|
+
# By default this list is empty.
|
19
|
+
def initial_state
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Resets the registered_items list to the list specified by the initial_state method.
|
24
|
+
def reset!
|
25
|
+
@registered_items = self.initial_state.dup
|
26
|
+
end
|
27
|
+
|
28
|
+
# Adds an object to the list at a specified position. By default the position is last.
|
29
|
+
def add(klass, position = self.registered_items.size)
|
30
|
+
self.registered_items.insert(position, klass)
|
31
|
+
self.registered_items.uniq!
|
32
|
+
self.registered_items.compact!
|
33
|
+
end
|
34
|
+
|
35
|
+
# Removes an object from the list.
|
36
|
+
def remove(klass)
|
37
|
+
self.registered_items.delete(klass)
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
|
42
|
+
# Returns the list of registered items.
|
43
|
+
def registered_items
|
44
|
+
self.instance.registered_items
|
45
|
+
end
|
46
|
+
|
47
|
+
# Emptys out the list of registered_items.
|
48
|
+
def clear!
|
49
|
+
registered_items.clear
|
50
|
+
end
|
51
|
+
|
52
|
+
# Resets the registered_items list to the list specified by the initial_state method.
|
53
|
+
def reset!
|
54
|
+
self.instance.reset!
|
55
|
+
end
|
56
|
+
|
57
|
+
# Adds an object to the list at a specified position. By default the position is last.
|
58
|
+
def add(klass, position = registered_items.size)
|
59
|
+
self.instance.add(klass, position)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Removes an object from the list.
|
63
|
+
def remove(klass)
|
64
|
+
self.instance.remove(klass)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Moves an object to the top of the registered_items list.
|
68
|
+
def move_to_top(klass)
|
69
|
+
self.instance.add(klass, 0)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Moves an object to the bottom of the registered_items list.
|
73
|
+
def move_to_bottom(klass)
|
74
|
+
remove(klass)
|
75
|
+
self.instance.add(klass)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end # RegistryList
|
81
|
+
end # Utils
|
82
|
+
end # BlabberMouth
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module BlabberMouth
|
2
|
+
# Includes the validatable gem into your Notifier.
|
3
|
+
# http://validatable.rubyforge.org
|
4
|
+
module Validatable
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.instance_eval do
|
8
|
+
include ::Validatable
|
9
|
+
alias_method "unvalidated_deliver!", "deliver!"
|
10
|
+
end
|
11
|
+
|
12
|
+
base.class_eval do
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
# Adds common validations to your BlabberMouth class.
|
17
|
+
# These include:
|
18
|
+
# validates_presence_of :to
|
19
|
+
# validates_presence_of :from
|
20
|
+
# validates_presence_of :subject
|
21
|
+
# validates_email_format_of :to
|
22
|
+
# validates_email_format_of :from
|
23
|
+
def common_notifier_validations
|
24
|
+
validates_presence_of :to
|
25
|
+
validates_presence_of :from
|
26
|
+
validates_presence_of :subject
|
27
|
+
validates_email_format_of :to
|
28
|
+
validates_email_format_of :from
|
29
|
+
end
|
30
|
+
|
31
|
+
# Validates the email format of the column specified against the email_validation_regex method.
|
32
|
+
# This will drill into arrays as well, if that's what your column is.
|
33
|
+
def validates_email_format_of(column, options = {})
|
34
|
+
options = {:logic => lambda{
|
35
|
+
[send(column)].flatten.each_with_index do |addr, i|
|
36
|
+
errors.add(column, "[#{addr}] is not valid") unless addr.to_s.downcase.match(self.class.email_validation_regex)
|
37
|
+
end
|
38
|
+
}}.merge(options)
|
39
|
+
validates_each :to, options
|
40
|
+
end
|
41
|
+
|
42
|
+
def email_validation_regex
|
43
|
+
regex = <<-EOF
|
44
|
+
[a-z0-9!#$\%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$\%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
|
45
|
+
EOF
|
46
|
+
/#{regex.strip}/
|
47
|
+
end
|
48
|
+
|
49
|
+
end # class << self
|
50
|
+
end # class_eval
|
51
|
+
end # included
|
52
|
+
|
53
|
+
# Raises a RuntimeError if the email you are trying to deliver is not valid.
|
54
|
+
def deliver!(handler = deliver_with)
|
55
|
+
raise 'Notification is Invalid!' unless self.valid?
|
56
|
+
unvalidated_deliver!(handler)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns false if the email is not valid.
|
60
|
+
# If the email is valid and an exception is raised when trying to deliver it
|
61
|
+
# false is returned and the exception is added to the errors array, with the
|
62
|
+
# key :deliver.
|
63
|
+
def deliver(handler = deliver_with)
|
64
|
+
return false unless self.valid?
|
65
|
+
begin
|
66
|
+
"BlabberMouth::DeliveryHandlers::#{handler.to_s.camelcase}".constantize.deliver(self)
|
67
|
+
rescue Exception => e
|
68
|
+
self.errors.add(:deliver, e.message)
|
69
|
+
return false
|
70
|
+
end
|
71
|
+
return true
|
72
|
+
end
|
73
|
+
|
74
|
+
def errors_for(name)
|
75
|
+
self.errors.on(name.to_sym)
|
76
|
+
end
|
77
|
+
|
78
|
+
end # Validatable
|
79
|
+
end # BlabberMouth
|
80
|
+
|
81
|
+
module Validatable # :nodoc:
|
82
|
+
class ValidationBase #:nodoc:
|
83
|
+
|
84
|
+
# This fixes a bug with reloading of Validatable classes.
|
85
|
+
def raise_error_if_key_is_dup(klass) # :nodoc:
|
86
|
+
vals = {}
|
87
|
+
klass.validations.each do |v|
|
88
|
+
vals[v.key] = v
|
89
|
+
end
|
90
|
+
klass.validations.clear
|
91
|
+
vals.each do |k,v|
|
92
|
+
klass.validations << v
|
93
|
+
end
|
94
|
+
end # raise_error_if_key_is_dup
|
95
|
+
|
96
|
+
end # ValidationBase
|
97
|
+
end # Validatable
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: markbates-blabber_mouth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.20090714164111
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- markbates
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-14 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: tmail
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.3.1
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: validatable
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.7
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: xmpp4r
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0.4"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: xmpp4r-simple
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.8.8
|
54
|
+
version:
|
55
|
+
description: "blabber_mouth was developed by: markbates"
|
56
|
+
email: ""
|
57
|
+
executables: []
|
58
|
+
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files:
|
62
|
+
- README
|
63
|
+
- LICENSE
|
64
|
+
files:
|
65
|
+
- lib/blabber_mouth/adapters/base.rb
|
66
|
+
- lib/blabber_mouth/adapters/tmail.rb
|
67
|
+
- lib/blabber_mouth/adapters/xmpp_msg.rb
|
68
|
+
- lib/blabber_mouth/attachment.rb
|
69
|
+
- lib/blabber_mouth/blabber_mouth.rb
|
70
|
+
- lib/blabber_mouth/delivery_handlers/sendmail.rb
|
71
|
+
- lib/blabber_mouth/delivery_handlers/smtp.rb
|
72
|
+
- lib/blabber_mouth/delivery_handlers/test.rb
|
73
|
+
- lib/blabber_mouth/delivery_handlers/xmpp_transport.rb
|
74
|
+
- lib/blabber_mouth/errors.rb
|
75
|
+
- lib/blabber_mouth/loader.rb
|
76
|
+
- lib/blabber_mouth/notifier_generator/manifest.yml
|
77
|
+
- lib/blabber_mouth/notifier_generator/notifier_generator.rb
|
78
|
+
- lib/blabber_mouth/notifier_generator/templates/app/notifiers/html.erb.template
|
79
|
+
- lib/blabber_mouth/notifier_generator/templates/app/notifiers/notifier.rb.template
|
80
|
+
- lib/blabber_mouth/notifier_generator/templates/app/notifiers/plain.erb.template
|
81
|
+
- lib/blabber_mouth/rendering/type/mailer.rb
|
82
|
+
- lib/blabber_mouth/settings.rb
|
83
|
+
- lib/blabber_mouth/testing.rb
|
84
|
+
- lib/blabber_mouth/utils/registry_list.rb
|
85
|
+
- lib/blabber_mouth/validations.rb
|
86
|
+
- lib/blabber_mouth.rb
|
87
|
+
- README
|
88
|
+
- LICENSE
|
89
|
+
has_rdoc: false
|
90
|
+
homepage: ""
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: "0"
|
101
|
+
version:
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: "0"
|
107
|
+
version:
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project: magrathea
|
111
|
+
rubygems_version: 1.2.0
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: blabber_mouth
|
115
|
+
test_files: []
|
116
|
+
|