markbates-blabber_mouth 0.1.0.20090714164111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|