sinatra_more 0.2.7 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -49,8 +49,8 @@ Here is a small list of what sinatra_more contains:
49
49
  * Asset tag helpers (<tt>link_to</tt>, <tt>image_tag</tt>, <tt>javascript_include_tag</tt>, ...)
50
50
  * Full form helpers and builders support (<tt>form_tag</tt>, <tt>form_for</tt>, <tt>field_set_tag</tt>, <tt>text_field</tt>, ...)
51
51
  * Generally useful formatting extensions (<tt>relative_time_ago</tt>, <tt>js_escape_html</tt>, <tt>sanitize_html</tt>)
52
+ * Simple 'mailer' support for sinatra (akin to <tt>ActionMailer</tt> but simpler and powered by <tt>pony</tt>)
52
53
  * Plug and play setup for the excellent Warden authentication system
53
- * Robust 'mailer' support for sinatra (akin to <tt>ActionMailer</tt> but simpler and powered by <tt>pony</tt>) (COMING SOON)
54
54
  * Code generators for creating a new sinatra application (COMING SOON)
55
55
 
56
56
  Keep in mind, the user will be able to pull in these components seperately and leave out those that are not required.
@@ -75,12 +75,13 @@ different components based on which pieces are useful for your particular applic
75
75
 
76
76
  # app.rb
77
77
  require 'sinatra/base'
78
- require 'sinatra_more'
78
+ require 'sinatra_more' # or require 'sinatra_more/markup_plugin' for precise inclusion
79
79
 
80
80
  class Application < Sinatra::Base
81
81
  register SinatraMore::MarkupPlugin
82
82
  register SinatraMore::RenderPlugin
83
83
  register SinatraMore::WardenPlugin
84
+ register SinatraMore::MailerPlugin
84
85
  end
85
86
 
86
87
  This will then allow you to use the components that have been registered. A breakdown of components is below:
@@ -467,10 +468,85 @@ Eventually I plan to vendor that gem or just remove support for this piece of my
467
468
  If anybody has any thoughts on this or the warden integration in general, please let me know.
468
469
  Nonetheless, there is a certain convenience for me having access to a plug-and-play warden solution directly from this gem.
469
470
 
471
+ === MailerPlugin
472
+
473
+ This component uses an enhanced version of the excellent <tt>pony</tt> library (vendored) for a powerful but simple
474
+ mailer system within Sinatra. There is full support for using an html content type as well as for file attachments.
475
+ The MailerPlugin has many similarities to ActionMailer but is much lighterweight and (arguably) easier to use.
476
+
477
+ Let's take a look at using the MailerPlugin in an application. By default, MailerPlugin uses the built-in sendmail
478
+ functionality on the server. However, smtp is also supported using the following configuration:
479
+
480
+ SinatraMore::MailerBase.smtp_settings = {
481
+ :host => 'smtp.gmail.com',
482
+ :port => '587',
483
+ :tls => true,
484
+ :user => 'user',
485
+ :pass => 'pass',
486
+ :auth => :plain
487
+ }
488
+
489
+ Once those have been defined, the default will become smtp delivery unless overwritten in an individual mail definition.
490
+ Next, we should define a custom mailer extended from <tt>SinatraMore::MailerBase</tt>.
491
+
492
+ class SampleMailer < SinatraMore::MailerBase
493
+ def registration_email(name, user_email_address)
494
+ from 'admin@site.com'
495
+ to user_email_address
496
+ subject 'Welcome to the site!'
497
+ body :name => name
498
+ type 'html' # optional, defaults to plain/text
499
+ charset 'windows-1252' # optional, defaults to utf-8
500
+ via :sendmail # optional, to smtp if defined otherwise sendmail
501
+ end
502
+ end
503
+
504
+ This defines a mail called '<tt>registration_mail</tt>' with the specified attributes for delivery. The <tt>body</tt> method
505
+ is passing the <tt>name</tt> attribute to the body message template which should be defined in
506
+ <tt>[views_path]/sample_mailer/registration_email.erb</tt> as shown below:
507
+
508
+ # ./views/sample_mailer/registration_email.erb
509
+ This is the body of the email and can access the <%= name %> that was passed in from the mailer definition
510
+ That's all there is to defining the body of the email which can be plain text or email
511
+
512
+ Once the mailer definition has been completed and the template has been defined, the email can be sent using:
513
+
514
+ SampleMailer.deliver(:registration_email, "Bob", "bob@bobby.com")
515
+
516
+ or if you like the method_missing approach:
517
+
518
+ SampleMailer.deliver_registration_email "Bob", 'bob@bobby.com'
519
+
520
+ And that will then deliver the email according the the configured options. This is really all you need to send emails.
521
+ A few variations are shown below for completeness.
522
+
523
+ If we want to attach files to our email:
524
+
525
+ class SampleMailer < SinatraMore::MailerBase
526
+ def attachment_email(name, user_email_address)
527
+ from 'admin@site.com'
528
+ to user_email_address
529
+ # ...
530
+ attachments { "foo.zip" => File.read("path/to/foo.zip"), "file.txt" => "this is a text file!" }
531
+ end
532
+ end
533
+
534
+ or perhaps we want to have a short body without the need for a template file:
535
+
536
+ class SampleMailer < SinatraMore::MailerBase
537
+ def short_email(name, user_email_address)
538
+ from 'admin@site.com'
539
+ to user_email_address
540
+ subject 'Welcome to the site!'
541
+ body "This is a short body defined right in the mailer itself"
542
+ end
543
+ end
544
+
470
545
  == Acknowledgements
471
546
 
472
- * Thanks to keldredd for the sinatra_helpers code that helped me to create erb capture and concat methods.
473
- * Thanks to sbfaulkner for the sinatra-helpers code that I browsed through many times while starting this library.
547
+ * Thanks to keldredd for the <tt>sinatra_helpers</tt> code that helped me to create erb capture and concat methods.
548
+ * Thanks to sbfaulkner for the <tt>sinatra-helpers</tt> code that I browsed through many times while starting this library.
549
+ * Thanks to vestel for the excellent modified <tt>pony</tt> fork which in part powers the mailer_plugin (http://github.com/vestel/pony)
474
550
 
475
551
  == Contributors
476
552
 
data/Rakefile CHANGED
@@ -12,6 +12,7 @@ begin
12
12
  gem.email = "nesquena@gmail.com"
13
13
  gem.homepage = "http://github.com/nesquena/sinatra_more"
14
14
  gem.authors = ["Nathan Esquenazi"]
15
+ gem.add_runtime_dependency "tilt", ">= 0.2"
15
16
  gem.add_runtime_dependency "sinatra", ">= 0.9.2"
16
17
  gem.add_runtime_dependency "activesupport", ">= 2.2.2"
17
18
  gem.add_development_dependency "haml", ">= 2.2.1"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.7
1
+ 0.2.8
@@ -0,0 +1,37 @@
1
+ # This represents a particular mail object which will need to be sent
2
+ # A mail_object requires the mail attributes and the delivery_settings
3
+
4
+ module SinatraMore
5
+ class MailObject
6
+ def initialize(mail_attributes={}, smtp_settings={})
7
+ @mail_attributes = mail_attributes.dup
8
+ @smtp_settings = smtp_settings.dup if smtp_settings.present?
9
+ end
10
+
11
+ # Constructs the delivery attributes for the message and then sends the mail
12
+ # @mail_object.deliver
13
+ def deliver
14
+ @mail_attributes.reverse_merge!(:via => self.delivery_method.to_sym)
15
+ @mail_attributes.reverse_merge!(:smtp => @smtp_settings) if using_smtp?
16
+ self.send_mail(@mail_attributes)
17
+ end
18
+
19
+ protected
20
+
21
+ # Returns the delivery method to use for this mail object
22
+ # @mo.delivery_method => :smtp || :sendmail
23
+ def delivery_method
24
+ @mail_attributes[:via] || (@smtp_settings.present? ? :smtp : :sendmail)
25
+ end
26
+
27
+ # Returns true if the mail object is going to be delivered using smtp
28
+ def using_smtp?
29
+ delivery_method.to_s =~ /smtp/
30
+ end
31
+
32
+ # Performs the actual email sending using a third-party library
33
+ def send_mail(delivery_attributes)
34
+ Pony.mail(delivery_attributes) && true
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,73 @@
1
+ =begin
2
+
3
+ This is the abstract class that other mailers will inherit from in order to send mail
4
+
5
+ You can set the default delivery settings through:
6
+
7
+ SinatraMore::MailerBase.smtp_settings = {
8
+ :host => 'smtp.yourserver.com',
9
+ :port => '25',
10
+ :user => 'user',
11
+ :pass => 'pass',
12
+ :auth => :plain # :plain, :login, :cram_md5, no auth by default
13
+ :domain => "localhost.localdomain" # the HELO domain provided by the client to the server
14
+ }
15
+
16
+ and then all delivered mail will use these settings unless otherwise specified.
17
+
18
+ =end
19
+
20
+ module SinatraMore
21
+ class MailerBase
22
+ # Returns the available mail fields when composing a message
23
+ def self.mail_fields
24
+ [:to, :from, :subject, :type, :charset, :via, :attachments]
25
+ end
26
+
27
+ attr_accessor :mail_attributes
28
+
29
+ def initialize(mail_name=nil)
30
+ @mail_name = mail_name
31
+ @mail_attributes = {}
32
+ end
33
+
34
+ # Defines a method allowing mail attributes to be set into a hash for use when delivering
35
+ self.mail_fields.each do |field|
36
+ define_method(field) { |value| @mail_attributes[field] = value }
37
+ end
38
+
39
+ # Assigns the body key to the mail attributes either with the rendered body from a template or the given string value
40
+ def body(body_value)
41
+ @mail_attributes[:body] = Tilt.new(template_path).render(self, body_value.symbolize_keys) if body_value.is_a?(Hash)
42
+ @mail_attributes[:body] = body_value if body_value.is_a?(String)
43
+ end
44
+
45
+ # Returns the path to the email template searched for using glob pattern
46
+ def template_path
47
+ Dir[File.join(self.views_path, self.class.name.underscore.split("/").last, "#{@mail_name}.*")].first
48
+ end
49
+
50
+ cattr_accessor :smtp_settings
51
+ cattr_accessor :views_path
52
+
53
+ # Delivers the specified message for mail_name to the intended recipients
54
+ # mail_name corresponds to the name of a defined method within the mailer class
55
+ # SampleMailer.deliver(:birthday_message)
56
+ def self.deliver(mail_name, *args)
57
+ mail_object = self.new(mail_name)
58
+ mail_object.method(mail_name).call(*args)
59
+ MailObject.new(mail_object.mail_attributes, self.smtp_settings).deliver
60
+ end
61
+
62
+ # Returns true if a mail exists with the name being delivered
63
+ def self.respond_to?(method_sym, include_private = false)
64
+ method_sym.to_s =~ /deliver_(.*)/ ? self.method_defined?($1) : super
65
+ end
66
+
67
+ # Handles method missing for a mailer class. Delivers a message based on the method
68
+ # being called i.e #deliver_birthday_message(22) invokes #birthday_message(22) to setup mail object
69
+ def self.method_missing(method_sym, *arguments, &block)
70
+ method_sym.to_s =~ /deliver_(.*)/ ? self.deliver($1, *arguments) : super
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,12 @@
1
+ require 'tilt'
2
+ require File.dirname(__FILE__) + '/support_lite'
3
+ require File.dirname(__FILE__) + '/../../vendor/pony/lib/pony'
4
+ Dir[File.dirname(__FILE__) + '/mailer_plugin/**/*.rb'].each { |file| load file }
5
+
6
+ module SinatraMore
7
+ module MailerPlugin
8
+ def self.registered(app)
9
+ MailerBase::views_path = app.views
10
+ end
11
+ end
12
+ end
data/lib/sinatra_more.rb CHANGED
@@ -3,3 +3,4 @@ require 'sinatra/base'
3
3
  require File.join(File.dirname(__FILE__) + '/sinatra_more/markup_plugin')
4
4
  require File.join(File.dirname(__FILE__) + '/sinatra_more/render_plugin')
5
5
  require File.join(File.dirname(__FILE__) + '/sinatra_more/warden_plugin')
6
+ require File.join(File.dirname(__FILE__) + '/sinatra_more/mailer_plugin')
data/sinatra_more.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{sinatra_more}
8
- s.version = "0.2.7"
8
+ s.version = "0.2.8"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nathan Esquenazi"]
12
- s.date = %q{2009-10-29}
12
+ s.date = %q{2009-11-03}
13
13
  s.description = %q{Expands sinatra with standard helpers and tools to allow for complex applications}
14
14
  s.email = %q{nesquena@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -25,6 +25,9 @@ Gem::Specification.new do |s|
25
25
  "TODO",
26
26
  "VERSION",
27
27
  "lib/sinatra_more.rb",
28
+ "lib/sinatra_more/mailer_plugin.rb",
29
+ "lib/sinatra_more/mailer_plugin/mail_object.rb",
30
+ "lib/sinatra_more/mailer_plugin/mailer_base.rb",
28
31
  "lib/sinatra_more/markup_plugin.rb",
29
32
  "lib/sinatra_more/markup_plugin/asset_tag_helpers.rb",
30
33
  "lib/sinatra_more/markup_plugin/form_builder/abstract_form_builder.rb",
@@ -40,6 +43,10 @@ Gem::Specification.new do |s|
40
43
  "lib/sinatra_more/warden_plugin/warden_helpers.rb",
41
44
  "sinatra_more.gemspec",
42
45
  "test/active_support_helpers.rb",
46
+ "test/fixtures/mailer_app/app.rb",
47
+ "test/fixtures/mailer_app/views/demo_mailer/sample_mail.erb",
48
+ "test/fixtures/mailer_app/views/sample_mailer/anniversary_message.erb",
49
+ "test/fixtures/mailer_app/views/sample_mailer/birthday_message.erb",
43
50
  "test/fixtures/markup_app/app.rb",
44
51
  "test/fixtures/markup_app/views/capture_concat.erb",
45
52
  "test/fixtures/markup_app/views/capture_concat.haml",
@@ -60,14 +67,20 @@ Gem::Specification.new do |s|
60
67
  "test/fixtures/warden_app/app.rb",
61
68
  "test/fixtures/warden_app/views/dashboard.haml",
62
69
  "test/helper.rb",
70
+ "test/mailer_plugin/test_mail_object.rb",
71
+ "test/mailer_plugin/test_mailer_base.rb",
63
72
  "test/markup_plugin/test_asset_tag_helpers.rb",
64
73
  "test/markup_plugin/test_form_builder.rb",
65
74
  "test/markup_plugin/test_form_helpers.rb",
66
75
  "test/markup_plugin/test_format_helpers.rb",
67
76
  "test/markup_plugin/test_output_helpers.rb",
68
77
  "test/markup_plugin/test_tag_helpers.rb",
78
+ "test/test_mailer_plugin.rb",
69
79
  "test/test_render_plugin.rb",
70
- "test/test_warden_plugin.rb"
80
+ "test/test_warden_plugin.rb",
81
+ "vendor/pony/lib/pony.rb",
82
+ "vendor/pony/spec/base.rb",
83
+ "vendor/pony/spec/pony_spec.rb"
71
84
  ]
72
85
  s.homepage = %q{http://github.com/nesquena/sinatra_more}
73
86
  s.rdoc_options = ["--charset=UTF-8"]
@@ -76,16 +89,20 @@ Gem::Specification.new do |s|
76
89
  s.summary = %q{Expands sinatra to allow for complex applications}
77
90
  s.test_files = [
78
91
  "test/active_support_helpers.rb",
92
+ "test/fixtures/mailer_app/app.rb",
79
93
  "test/fixtures/markup_app/app.rb",
80
94
  "test/fixtures/render_app/app.rb",
81
95
  "test/fixtures/warden_app/app.rb",
82
96
  "test/helper.rb",
97
+ "test/mailer_plugin/test_mail_object.rb",
98
+ "test/mailer_plugin/test_mailer_base.rb",
83
99
  "test/markup_plugin/test_asset_tag_helpers.rb",
84
100
  "test/markup_plugin/test_form_builder.rb",
85
101
  "test/markup_plugin/test_form_helpers.rb",
86
102
  "test/markup_plugin/test_format_helpers.rb",
87
103
  "test/markup_plugin/test_output_helpers.rb",
88
104
  "test/markup_plugin/test_tag_helpers.rb",
105
+ "test/test_mailer_plugin.rb",
89
106
  "test/test_render_plugin.rb",
90
107
  "test/test_warden_plugin.rb"
91
108
  ]
@@ -95,6 +112,7 @@ Gem::Specification.new do |s|
95
112
  s.specification_version = 3
96
113
 
97
114
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
115
+ s.add_runtime_dependency(%q<tilt>, [">= 0.2"])
98
116
  s.add_runtime_dependency(%q<sinatra>, [">= 0.9.2"])
99
117
  s.add_runtime_dependency(%q<activesupport>, [">= 2.2.2"])
100
118
  s.add_development_dependency(%q<haml>, [">= 2.2.1"])
@@ -103,6 +121,7 @@ Gem::Specification.new do |s|
103
121
  s.add_development_dependency(%q<rack-test>, [">= 0.5.0"])
104
122
  s.add_development_dependency(%q<webrat>, [">= 0.5.1"])
105
123
  else
124
+ s.add_dependency(%q<tilt>, [">= 0.2"])
106
125
  s.add_dependency(%q<sinatra>, [">= 0.9.2"])
107
126
  s.add_dependency(%q<activesupport>, [">= 2.2.2"])
108
127
  s.add_dependency(%q<haml>, [">= 2.2.1"])
@@ -112,6 +131,7 @@ Gem::Specification.new do |s|
112
131
  s.add_dependency(%q<webrat>, [">= 0.5.1"])
113
132
  end
114
133
  else
134
+ s.add_dependency(%q<tilt>, [">= 0.2"])
115
135
  s.add_dependency(%q<sinatra>, [">= 0.9.2"])
116
136
  s.add_dependency(%q<activesupport>, [">= 2.2.2"])
117
137
  s.add_dependency(%q<haml>, [">= 2.2.1"])
@@ -0,0 +1,51 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra_more'
3
+ require 'haml'
4
+
5
+ class MailerDemo < Sinatra::Base
6
+ configure do
7
+ set :root, File.dirname(__FILE__)
8
+ set :smtp_settings, {
9
+ :host => 'smtp.gmail.com',
10
+ :port => '587',
11
+ :tls => true,
12
+ :user => 'user',
13
+ :pass => 'pass',
14
+ :auth => :plain
15
+ }
16
+ end
17
+
18
+ register SinatraMore::MailerPlugin
19
+
20
+ class SampleMailer < SinatraMore::MailerBase
21
+ def birthday_message(name, age)
22
+ subject "Happy Birthday!"
23
+ to 'john@fake.com'
24
+ from 'noreply@birthday.com'
25
+ body 'name' => name, 'age' => age
26
+ via :smtp
27
+ end
28
+
29
+ def anniversary_message(names, years_married)
30
+ subject "Happy anniversary!"
31
+ to 'julie@fake.com'
32
+ from 'noreply@anniversary.com'
33
+ body 'names' => names, 'years_married' => years_married
34
+ type 'html'
35
+ end
36
+ end
37
+
38
+ post "/deliver/plain" do
39
+ result = SampleMailer.deliver_birthday_message("Joey", 21)
40
+ result ? "mail delivered" : 'mail not delivered'
41
+ end
42
+
43
+ post "/deliver/html" do
44
+ result = SampleMailer.deliver_anniversary_message("Joey & Charlotte", 16)
45
+ result ? "mail delivered" : 'mail not delivered'
46
+ end
47
+ end
48
+
49
+ class MailerUser
50
+
51
+ end
@@ -0,0 +1 @@
1
+ This is a sample message
@@ -0,0 +1,2 @@
1
+ <p>Yay <%= names %>!</p>
2
+ <p>You have been married <%= years_married %> years</p>
@@ -0,0 +1,2 @@
1
+ Happy Birthday <%= name %>!
2
+ You are turning <%= age %>
@@ -0,0 +1,24 @@
1
+ require 'helper'
2
+ require 'sinatra_more'
3
+
4
+ class TestMailObject < Test::Unit::TestCase
5
+ context 'for #deliver method' do
6
+ should "send mail with attributes default to sendmail no smtp" do
7
+ mail_object = SinatraMore::MailObject.new({:to => "test@john.com", :from => "sender@sent.com", :body => "Hello"}, {})
8
+ Pony.expects(:mail).with(:to => "test@john.com", :from => "sender@sent.com", :body => "Hello", :via => :sendmail)
9
+ mail_object.deliver
10
+ end
11
+
12
+ should "send mail with attributes default to smtp if set" do
13
+ mail_object = SinatraMore::MailObject.new({:to => "test@john.com", :body => "Hello"}, { :host => 'smtp.gmail.com' })
14
+ Pony.expects(:mail).with(:to => "test@john.com", :body => "Hello", :via => :smtp, :smtp => { :host => 'smtp.gmail.com' })
15
+ mail_object.deliver
16
+ end
17
+
18
+ should "send mail with attributes use sendmail if explicit" do
19
+ mail_object = SinatraMore::MailObject.new({:to => "test@john.com", :via => :sendmail }, { :host => 'smtp.gmail.com' })
20
+ Pony.expects(:mail).with(:to => "test@john.com", :via => :sendmail)
21
+ mail_object.deliver
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,81 @@
1
+ require 'helper'
2
+ require 'sinatra_more'
3
+
4
+ class DemoMailer < SinatraMore::MailerBase
5
+ def sample_mail
6
+ from 'test@default.com'
7
+ to 'test@test.com'
8
+ body "Hello world!"
9
+ via :sendmail
10
+ end
11
+
12
+ def sample_mail_smtp
13
+ from 'test@default.com'
14
+ to 'test@test.com'
15
+ body "SMTP Hello world!"
16
+ end
17
+ end
18
+
19
+ class TestMailerBase < Test::Unit::TestCase
20
+ context 'for defining email attributes' do
21
+ DemoMailer.mail_fields.each do |field|
22
+ should "support setting '#{field}' attribute" do
23
+ demo_mailer = DemoMailer.new(:sample_mail)
24
+ demo_mailer.send(field, "some_value")
25
+ assert_equal({ field => "some_value" }, demo_mailer.mail_attributes)
26
+ end
27
+ end
28
+
29
+ should "allow defining text body" do
30
+ demo_mailer = DemoMailer.new(:sample_mail)
31
+ demo_mailer.body("Hello world!")
32
+ assert_equal({ :body => "Hello world!" }, demo_mailer.mail_attributes)
33
+ end
34
+ end
35
+
36
+ context 'for retrieving template path' do
37
+ should "return correct path" do
38
+ demo_mailer = DemoMailer.new(:sample_mail)
39
+ assert_match %r{demo_mailer/sample_mail.erb}, demo_mailer.template_path
40
+ end
41
+ end
42
+
43
+ context 'for #deliver class method' do
44
+ should "perform the email delivery for sendmail" do
45
+ Pony.expects(:mail).with(:from => 'test@default.com', :to => 'test@test.com', :body => "Hello world!", :via => :sendmail)
46
+ DemoMailer.deliver(:sample_mail)
47
+ end
48
+
49
+ should "perform the email delivery for smtp" do
50
+ DemoMailer.smtp_settings = { :host => 'smtp.arcadic.com' }
51
+ Pony.expects(:mail).with(:from => 'test@default.com', :to => 'test@test.com',
52
+ :body => "SMTP Hello world!", :via => :smtp, :smtp => { :host => 'smtp.arcadic.com' })
53
+ DemoMailer.deliver(:sample_mail_smtp)
54
+ end
55
+ end
56
+
57
+ context 'for #respond_to? class method' do
58
+ should "respond as true for any delivery method calls for mails that exist" do
59
+ assert DemoMailer.respond_to?(:deliver_sample_mail)
60
+ end
61
+
62
+ should "respond as false for any delivery method calls for mails that don't exist" do
63
+ assert_equal false, DemoMailer.respond_to?(:deliver_faker_mail)
64
+ end
65
+
66
+ should "respond as true for any non-delivery methods that exist" do
67
+ assert DemoMailer.respond_to?(:inspect)
68
+ end
69
+
70
+ should "respond as false for any non-delivery methods that don't exist" do
71
+ assert_equal false, DemoMailer.respond_to?(:fake_method)
72
+ end
73
+ end
74
+
75
+ context 'for #method_missing dynamic delivery' do
76
+ should 'invoke deliver method with appropriate parameters' do
77
+ DemoMailer.expects(:deliver).with("example_name", "test", 5)
78
+ DemoMailer.deliver_example_name("test", 5)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,33 @@
1
+ require 'helper'
2
+ require 'fixtures/mailer_app/app'
3
+
4
+ class TestMailerPlugin < Test::Unit::TestCase
5
+ def app
6
+ MailerDemo.tap { |app| app.set :environment, :test }
7
+ end
8
+
9
+ context 'for mail delivery in sample application' do
10
+ setup { MailerDemo::SampleMailer.smtp_settings = MailerDemo.smtp_settings }
11
+
12
+ should 'be able to deliver plain text emails' do
13
+ assert_email_sent(:to => 'john@fake.com', :from => 'noreply@birthday.com', :via => :smtp,
14
+ :subject => "Happy Birthday!", :body => "Happy Birthday Joey! \nYou are turning 21")
15
+ visit '/deliver/plain', :post
16
+ assert_equal 'mail delivered', last_response.body
17
+ end
18
+
19
+ should 'be able to deliver html emails' do
20
+ assert_email_sent(:to => 'julie@fake.com', :from => 'noreply@anniversary.com', :type => 'html', :via => :smtp,
21
+ :subject => "Happy anniversary!", :body => "<p>Yay Joey & Charlotte!</p>\n<p>You have been married 16 years</p>")
22
+ visit '/deliver/html', :post
23
+ assert_equal 'mail delivered', last_response.body
24
+ end
25
+ end
26
+
27
+ protected
28
+
29
+ def assert_email_sent(mail_attributes)
30
+ delivery_attributes = mail_attributes.merge(:smtp => MailerDemo.smtp_settings)
31
+ SinatraMore::MailObject.any_instance.expects(:send_mail).with(delivery_attributes).once.returns(true)
32
+ end
33
+ end
@@ -0,0 +1,90 @@
1
+ require 'rubygems'
2
+ require 'net/smtp'
3
+ begin
4
+ require 'smtp_tls'
5
+ rescue LoadError
6
+ end
7
+ require 'base64'
8
+ begin
9
+ require 'tmail'
10
+ rescue LoadError
11
+ require 'actionmailer'
12
+ end
13
+
14
+ module Pony
15
+ def self.mail(options)
16
+ raise(ArgumentError, ":to is required") unless options[:to]
17
+
18
+ via = options.delete(:via)
19
+ if via.nil?
20
+ transport build_tmail(options)
21
+ else
22
+ if via_options.include?(via.to_s)
23
+ send("transport_via_#{via}", build_tmail(options), options)
24
+ else
25
+ raise(ArgumentError, ":via must be either smtp or sendmail")
26
+ end
27
+ end
28
+ end
29
+
30
+ def self.build_tmail(options)
31
+ mail = TMail::Mail.new
32
+ mail.to = options[:to]
33
+ mail.from = options[:from] || 'pony@unknown'
34
+ mail.subject = options[:subject]
35
+ mail.body = options[:body] || ""
36
+ mail.set_content_type 'text', options[:type] || 'plain', {'charset'=> options[:charset] || 'utf-8'}
37
+ (options[:attachments] || []).each do |name, body|
38
+ attachment = TMail::Mail.new
39
+ attachment.transfer_encoding = "base64"
40
+ attachment.body = Base64.encode64(body)
41
+ # attachment.set_content_type # TODO: if necessary
42
+ attachment.set_content_disposition "attachment", "filename" => name
43
+ mail.parts.push attachment
44
+ end
45
+ mail
46
+ end
47
+
48
+ def self.sendmail_binary
49
+ @sendmail_binary ||= `which sendmail`.chomp
50
+ end
51
+
52
+ def self.transport(tmail)
53
+ if File.executable? sendmail_binary
54
+ transport_via_sendmail(tmail)
55
+ else
56
+ transport_via_smtp(tmail)
57
+ end
58
+ end
59
+
60
+ def self.via_options
61
+ %w(sendmail smtp)
62
+ end
63
+
64
+ def self.transport_via_sendmail(tmail, options={})
65
+ IO.popen('-', 'w+') do |pipe|
66
+ if pipe
67
+ pipe.write(tmail.to_s)
68
+ else
69
+ exec(sendmail_binary, *tmail.to)
70
+ end
71
+ end
72
+ end
73
+
74
+ def self.transport_via_smtp(tmail, options={:smtp => {}})
75
+ default_options = {:smtp => { :host => 'localhost', :port => '25', :domain => 'localhost.localdomain' }}
76
+ o = default_options[:smtp].merge(options[:smtp])
77
+ smtp = Net::SMTP.new(o[:host], o[:port])
78
+ if o[:tls]
79
+ raise "You may need: gem install smtp_tls" unless smtp.respond_to?(:enable_starttls)
80
+ smtp.enable_starttls
81
+ end
82
+ if o.include?(:auth)
83
+ smtp.start(o[:domain], o[:user], o[:password], o[:auth])
84
+ else
85
+ smtp.start(o[:domain])
86
+ end
87
+ smtp.send_message tmail.to_s, tmail.from, tmail.to
88
+ smtp.finish
89
+ end
90
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/pony'
@@ -0,0 +1,147 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Pony do
4
+ it "sends mail" do
5
+ Pony.should_receive(:transport) do |tmail|
6
+ tmail.to.should == [ 'joe@example.com' ]
7
+ tmail.from.should == [ 'sender@example.com' ]
8
+ tmail.subject.should == 'hi'
9
+ tmail.body.should == 'Hello, Joe.'
10
+ end
11
+ Pony.mail(:to => 'joe@example.com', :from => 'sender@example.com', :subject => 'hi', :body => 'Hello, Joe.')
12
+ end
13
+
14
+ it "requires :to param" do
15
+ Pony.stub!(:transport)
16
+ lambda { Pony.mail({}) }.should raise_error(ArgumentError)
17
+ end
18
+
19
+ it "doesn't require any other param" do
20
+ Pony.stub!(:transport)
21
+ lambda { Pony.mail(:to => 'joe@example.com') }.should_not raise_error
22
+ end
23
+
24
+ ####################
25
+
26
+ describe "builds a TMail object with field:" do
27
+ it "to" do
28
+ Pony.build_tmail(:to => 'joe@example.com').to.should == [ 'joe@example.com' ]
29
+ end
30
+
31
+ it "from" do
32
+ Pony.build_tmail(:from => 'joe@example.com').from.should == [ 'joe@example.com' ]
33
+ end
34
+
35
+ it "from (default)" do
36
+ Pony.build_tmail({}).from.should == [ 'pony@unknown' ]
37
+ end
38
+
39
+ it "subject" do
40
+ Pony.build_tmail(:subject => 'hello').subject.should == 'hello'
41
+ end
42
+
43
+ it "body" do
44
+ Pony.build_tmail(:body => 'What do you know, Joe?').body.should == 'What do you know, Joe?'
45
+ end
46
+
47
+ it "type" do
48
+ Pony.build_tmail(:type => 'html').content_type.should == 'text/html'
49
+ end
50
+
51
+ it "charset" do
52
+ Pony.build_tmail(:charset => 'windows-1252').charset.should == 'windows-1252'
53
+ end
54
+
55
+ it "attachments" do
56
+ tmail = Pony.build_tmail(:attachments => {"foo.txt" => "content of foo.txt"})
57
+ tmail.should have(1).parts
58
+ tmail.parts.first.to_s.should == <<-PART
59
+ Content-Transfer-Encoding: Base64
60
+ Content-Disposition: attachment; filename=foo.txt
61
+
62
+ Y29udGVudCBvZiBmb28udHh0
63
+ PART
64
+ end
65
+ end
66
+
67
+ describe "transport" do
68
+ it "transports via the sendmail binary if it exists" do
69
+ File.stub!(:executable?).and_return(true)
70
+ Pony.should_receive(:transport_via_sendmail).with(:tmail)
71
+ Pony.transport(:tmail)
72
+ end
73
+
74
+ it "transports via smtp if no sendmail binary" do
75
+ Pony.stub!(:sendmail_binary).and_return('/does/not/exist')
76
+ Pony.should_receive(:transport_via_smtp).with(:tmail)
77
+ Pony.transport(:tmail)
78
+ end
79
+
80
+ it "transports mail via /usr/sbin/sendmail binary" do
81
+ pipe = mock('sendmail pipe')
82
+ IO.should_receive(:popen).with('-',"w+").and_yield(pipe)
83
+ pipe.should_receive(:write).with('message')
84
+ Pony.transport_via_sendmail(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
85
+ end
86
+
87
+ describe "SMTP transport" do
88
+ before do
89
+ @smtp = mock('net::smtp object')
90
+ @smtp.stub!(:start)
91
+ @smtp.stub!(:send_message)
92
+ @smtp.stub!(:finish)
93
+ Net::SMTP.stub!(:new).and_return(@smtp)
94
+ end
95
+
96
+ it "defaults to localhost as the SMTP server" do
97
+ Net::SMTP.should_receive(:new).with('localhost', '25').and_return(@smtp)
98
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
99
+ end
100
+
101
+ it "uses SMTP authorization when auth key is provided" do
102
+ o = { :smtp => { :user => 'user', :password => 'password', :auth => 'plain'}}
103
+ @smtp.should_receive(:start).with('localhost.localdomain', 'user', 'password', 'plain')
104
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'), o)
105
+ end
106
+
107
+ it "enable starttls when tls option is true" do
108
+ o = { :smtp => { :user => 'user', :password => 'password', :auth => 'plain', :tls => true}}
109
+ @smtp.should_receive(:enable_starttls)
110
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'), o)
111
+ end
112
+
113
+ it "starts the job" do
114
+ @smtp.should_receive(:start)
115
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
116
+ end
117
+
118
+ it "sends a tmail message" do
119
+ @smtp.should_receive(:send_message)
120
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
121
+ end
122
+
123
+ it "finishes the job" do
124
+ @smtp.should_receive(:finish)
125
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
126
+ end
127
+
128
+ end
129
+ end
130
+
131
+ describe ":via option should over-ride the default transport mechanism" do
132
+ it "should send via sendmail if :via => sendmail" do
133
+ Pony.should_receive(:transport_via_sendmail)
134
+ Pony.mail(:to => 'joe@example.com', :via => :sendmail)
135
+ end
136
+
137
+ it "should send via smtp if :via => smtp" do
138
+ Pony.should_receive(:transport_via_smtp)
139
+ Pony.mail(:to => 'joe@example.com', :via => :smtp)
140
+ end
141
+
142
+ it "should raise an error if via is neither smtp nor sendmail" do
143
+ lambda { Pony.mail(:to => 'joe@plumber.com', :via => :pigeon) }.should raise_error(ArgumentError)
144
+ end
145
+ end
146
+
147
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra_more
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Esquenazi
@@ -9,9 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-29 00:00:00 -07:00
12
+ date: 2009-11-03 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: tilt
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0.2"
24
+ version:
15
25
  - !ruby/object:Gem::Dependency
16
26
  name: sinatra
17
27
  type: :runtime
@@ -100,6 +110,9 @@ files:
100
110
  - TODO
101
111
  - VERSION
102
112
  - lib/sinatra_more.rb
113
+ - lib/sinatra_more/mailer_plugin.rb
114
+ - lib/sinatra_more/mailer_plugin/mail_object.rb
115
+ - lib/sinatra_more/mailer_plugin/mailer_base.rb
103
116
  - lib/sinatra_more/markup_plugin.rb
104
117
  - lib/sinatra_more/markup_plugin/asset_tag_helpers.rb
105
118
  - lib/sinatra_more/markup_plugin/form_builder/abstract_form_builder.rb
@@ -115,6 +128,10 @@ files:
115
128
  - lib/sinatra_more/warden_plugin/warden_helpers.rb
116
129
  - sinatra_more.gemspec
117
130
  - test/active_support_helpers.rb
131
+ - test/fixtures/mailer_app/app.rb
132
+ - test/fixtures/mailer_app/views/demo_mailer/sample_mail.erb
133
+ - test/fixtures/mailer_app/views/sample_mailer/anniversary_message.erb
134
+ - test/fixtures/mailer_app/views/sample_mailer/birthday_message.erb
118
135
  - test/fixtures/markup_app/app.rb
119
136
  - test/fixtures/markup_app/views/capture_concat.erb
120
137
  - test/fixtures/markup_app/views/capture_concat.haml
@@ -135,14 +152,20 @@ files:
135
152
  - test/fixtures/warden_app/app.rb
136
153
  - test/fixtures/warden_app/views/dashboard.haml
137
154
  - test/helper.rb
155
+ - test/mailer_plugin/test_mail_object.rb
156
+ - test/mailer_plugin/test_mailer_base.rb
138
157
  - test/markup_plugin/test_asset_tag_helpers.rb
139
158
  - test/markup_plugin/test_form_builder.rb
140
159
  - test/markup_plugin/test_form_helpers.rb
141
160
  - test/markup_plugin/test_format_helpers.rb
142
161
  - test/markup_plugin/test_output_helpers.rb
143
162
  - test/markup_plugin/test_tag_helpers.rb
163
+ - test/test_mailer_plugin.rb
144
164
  - test/test_render_plugin.rb
145
165
  - test/test_warden_plugin.rb
166
+ - vendor/pony/lib/pony.rb
167
+ - vendor/pony/spec/base.rb
168
+ - vendor/pony/spec/pony_spec.rb
146
169
  has_rdoc: true
147
170
  homepage: http://github.com/nesquena/sinatra_more
148
171
  licenses: []
@@ -173,15 +196,19 @@ specification_version: 3
173
196
  summary: Expands sinatra to allow for complex applications
174
197
  test_files:
175
198
  - test/active_support_helpers.rb
199
+ - test/fixtures/mailer_app/app.rb
176
200
  - test/fixtures/markup_app/app.rb
177
201
  - test/fixtures/render_app/app.rb
178
202
  - test/fixtures/warden_app/app.rb
179
203
  - test/helper.rb
204
+ - test/mailer_plugin/test_mail_object.rb
205
+ - test/mailer_plugin/test_mailer_base.rb
180
206
  - test/markup_plugin/test_asset_tag_helpers.rb
181
207
  - test/markup_plugin/test_form_builder.rb
182
208
  - test/markup_plugin/test_form_helpers.rb
183
209
  - test/markup_plugin/test_format_helpers.rb
184
210
  - test/markup_plugin/test_output_helpers.rb
185
211
  - test/markup_plugin/test_tag_helpers.rb
212
+ - test/test_mailer_plugin.rb
186
213
  - test/test_render_plugin.rb
187
214
  - test/test_warden_plugin.rb