qu-mailer 1.0.0rc1

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/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # Qu::Mailer
2
+
3
+ A gem plugin which allows messages prepared by ActionMailer to be delivered
4
+ asynchronously. Assumes you're using [Qu](https://github.com/bkeepers/qu)
5
+ for your background jobs.
6
+
7
+ Note that Qu::Mailer only work with Rails 3.x.
8
+
9
+ ## Usage
10
+
11
+ Include Qu::Mailer in your ActionMailer subclass(es) like this:
12
+
13
+ class MyMailer < ActionMailer::Base
14
+ include Qu::Mailer
15
+ end
16
+
17
+ Now, when @MyMailer.subject_email(params).deliver@ is called, an entry
18
+ will be created in the job queue. Your Qu workers will be able to deliver
19
+ this message for you. The queue we're using is imaginatively named **mailer**,
20
+ so just make sure your workers know about it and are loading your environment:
21
+
22
+ bundle exec rake environment qu:work QUEUES=mailer
23
+
24
+ Note that you can still have mail delivered synchronously by using the bang
25
+ method variant:
26
+
27
+ MyMailer.subject_email(params).deliver!
28
+
29
+ Oh, by the way. Don't forget that your async mailer jobs will be processed by
30
+ a separate worker. This means that you should resist the temptation to pass
31
+ database-backed objects as parameters in your mailer and instead pass record
32
+ identifiers. Then, in your delivery method, you can look up the record from
33
+ the id and use it as needed.
34
+
35
+ If you want to set a different default queue name for your mailer, you can
36
+ change the @default_queue_name@ property like so:
37
+
38
+ # config/initializers/qu_mailer.rb
39
+ Qu::Mailer.default_queue_name = 'application_specific_mailer'
40
+
41
+ This is useful when you are running more than one application using
42
+ Qu::Maile in a shared environment. You will need to use the new queue
43
+ name when starting your workers.
44
+
45
+ bundle exec rake environment qu:work QUEUES=application_specific_mailer
46
+
47
+ ## Qu::Mailer as a Project Default
48
+
49
+ If you have a variety of mailers in your application and want all of them to use
50
+ Qu::Mailer by default, you can subclass ActionMailer::Base and have your
51
+ other mailers inherit from an AsyncMailer:
52
+
53
+ # config/initializers/qu_mailer.rb
54
+ class BackgroundMailer < ActionMailer::Base
55
+ include Qu::Mailer
56
+ end
57
+
58
+ # app/mailers/example_mailer.rb
59
+ class ExampleMailer < AsyncMailer
60
+ def say_hello(user)
61
+ # ...
62
+ end
63
+ end
64
+
65
+ ## Installation
66
+
67
+ # Rails 3.x: add it to your Gemfile
68
+ gem 'qu-mailer'
69
+
70
+ ## Testing
71
+
72
+ You don't want to be sending actual emails in the test environment, so you can
73
+ configure the environments that should be excluded like so:
74
+
75
+ # config/initializers/qu_mailer.rb
76
+ Qu::Mailer.excluded_environments = [ :test, :cucumber ]
77
+
78
+ ## Note on Patches / Pull Requests
79
+
80
+ * Fork the project.
81
+ * Make your feature addition or bug fix.
82
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
83
+ * Commit, do not mess with rakefile, version, or history.
84
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
85
+ * Send me a pull request. Bonus points for topic branches.
86
+
87
+ ## Credits
88
+
89
+ This work is a port of [ResqueMailer](https://github.com/zapnap/resque_mailer) by Nick Plante.
90
+ Modified to work with the Qu queueing library by Morton Jonuschat.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'QuMailer'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task :default => :test
data/lib/qu-mailer.rb ADDED
@@ -0,0 +1 @@
1
+ require 'qu/mailer'
data/lib/qu/mailer.rb ADDED
@@ -0,0 +1,63 @@
1
+ module Qu
2
+ module Mailer
3
+ autoload :MessageDecoy, 'qu/mailer/message_decoy'
4
+
5
+ class << self
6
+ attr_accessor :default_queue_name, :default_queue_target
7
+ attr_reader :excluded_environments
8
+
9
+ def excluded_environments=(envs)
10
+ @excluded_environments = [*envs].map { |e| e.to_sym }
11
+ end
12
+
13
+ def included(base)
14
+ base.extend(ClassMethods)
15
+ end
16
+ end
17
+
18
+ # Defaults
19
+ self.default_queue_target = ::Qu
20
+ self.default_queue_name = 'mailer'
21
+ self.excluded_environments = [ :test ]
22
+
23
+ module ClassMethods
24
+ def current_env
25
+ ::Rails.env
26
+ end
27
+
28
+ def method_missing(method_name, *args)
29
+ return super if environment_excluded?
30
+
31
+ if action_methods.include?(method_name.to_s)
32
+ MessageDecoy.new(self, method_name, *args)
33
+ else
34
+ super
35
+ end
36
+ end
37
+
38
+ def perform(action, *args)
39
+ self.send(:new, action, *args).message.deliver
40
+ end
41
+
42
+ def environment_excluded?
43
+ !ActionMailer::Base.perform_deliveries || excluded_environment?(current_env)
44
+ end
45
+
46
+ def queue
47
+ ::Qu::Mailer.default_queue_name
48
+ end
49
+
50
+ def qu
51
+ ::Qu::Mailer.default_queue_target
52
+ end
53
+
54
+ def excluded_environment?(name)
55
+ ::Qu::Mailer.excluded_environments && ::Qu::Mailer.excluded_environments.include?(name.to_sym)
56
+ end
57
+
58
+ def deliver?
59
+ true
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,33 @@
1
+ module Qu
2
+ module Mailer
3
+ class MessageDecoy
4
+ def initialize(mailer_class, method_name, *args)
5
+ @mailer_class = mailer_class
6
+ @method_name = method_name
7
+ *@args = *args
8
+ end
9
+
10
+ def qu
11
+ ::Qu::Mailer.default_queue_target
12
+ end
13
+
14
+ def actual_message
15
+ @actual_message ||= @mailer_class.send(:new, @method_name, *@args).message
16
+ end
17
+
18
+ def deliver
19
+ if @mailer_class.deliver?
20
+ qu.enqueue(@mailer_class, @method_name, *@args)
21
+ end
22
+ end
23
+
24
+ def deliver!
25
+ actual_message.deliver!
26
+ end
27
+
28
+ def method_missing(method_name, *args)
29
+ actual_message.send(method_name, *args)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ module Qu
2
+ module Mailer
3
+ VERSION = "1.0.0rc1"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :qu_mailer do
3
+ # # Task goes here
4
+ # end
File without changes
File without changes
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe Qu::Mailer do
4
+ let(:qu) { FakeQu }
5
+
6
+ before do
7
+ Qu::Mailer.default_queue_target = qu
8
+ Qu::Mailer.stub(:success!)
9
+ TestMailer.stub(:current_env => :test)
10
+ end
11
+
12
+ describe "backend" do
13
+ it "allows overriding the default queue target for test purposes" do
14
+ Qu::Mailer.default_queue_target = FakeQu
15
+ TestMailer.qu.should == FakeQu
16
+ end
17
+ end
18
+
19
+ it 'should use "mailer" as the default queue name' do
20
+ TestMailer.queue.should == 'mailer'
21
+ end
22
+
23
+ it 'should allow overriding the default queue name' do
24
+ Qu::Mailer.default_queue_name = 'postal'
25
+ TestMailer.queue.should == 'postal'
26
+ end
27
+
28
+ describe '#deliver' do
29
+ before(:all) do
30
+ @delivery = lambda { TestMailer.test_mail(TestMailer::MAIL_PARAMS).deliver }
31
+ end
32
+
33
+ it 'should not perform synchronous deliveries' do
34
+ lambda { @delivery.call }.should_not change(ActionMailer::Base.deliveries, :size)
35
+ end
36
+
37
+ it 'should place the deliver action on the Qu "mailer" queue' do
38
+ qu.should_receive(:enqueue).with(TestMailer, :test_mail, TestMailer::MAIL_PARAMS)
39
+ @delivery.call
40
+ end
41
+
42
+ context "with the the current environment excluded" do
43
+ it 'should not deliver asynchronously' do
44
+ Qu::Mailer.stub(:excluded_environments).and_return([:custom])
45
+ TestMailer.should_receive(:current_env).and_return(:custom)
46
+ qu.should_not_receive(:enqueue)
47
+ @delivery.call
48
+ end
49
+ end
50
+
51
+ it 'should not invoke the body method more than once' do
52
+ Qu::Mailer.should_not_receive(:success!)
53
+ TestMailer.test_mail(TestMailer::MAIL_PARAMS).deliver
54
+ end
55
+ end
56
+
57
+ describe '#deliver!' do
58
+ it 'should deliver the email sychronously' do
59
+ lambda { TestMailer.test_mail(TestMailer::MAIL_PARAMS).deliver! }.should change(ActionMailer::Base.deliveries, :size).by(1)
60
+ end
61
+ end
62
+
63
+ describe '#perform' do
64
+ it 'should trigger delivery of a queued job' do
65
+ lambda { TestMailer.perform(:test_mail, TestMailer::MAIL_PARAMS) }.should change(ActionMailer::Base.deliveries, :size).by(1)
66
+ end
67
+ end
68
+
69
+ describe 'original mail methods' do
70
+ it 'should be preserved' do
71
+ TestMailer.test_mail(TestMailer::MAIL_PARAMS).subject.should == 'Subject'
72
+ TestMailer.test_mail(TestMailer::MAIL_PARAMS).from.should include('jane.doe@example.com')
73
+ TestMailer.test_mail(TestMailer::MAIL_PARAMS).to.should include('john.doe@example.com')
74
+ end
75
+
76
+ it 'should render the body before queuing' do
77
+ Qu::Mailer.should_receive(:success!).once
78
+ TestMailer.test_mail(TestMailer::MAIL_PARAMS).subject
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,12 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+
7
+ require 'action_mailer'
8
+ require 'qu-mailer'
9
+ require 'rspec/autorun'
10
+
11
+ # Load support files
12
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
@@ -0,0 +1 @@
1
+ ActionMailer::Base.delivery_method = :test
@@ -0,0 +1 @@
1
+ Qu::Mailer.excluded_environments = []
@@ -0,0 +1,6 @@
1
+ class FakeQu
2
+ class << self
3
+ def enqueue(*args)
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ class TestMailer < ActionMailer::Base
2
+ include Qu::Mailer
3
+ default :from => "jane.doe@example.com",
4
+ :subject => "Subject"
5
+
6
+ MAIL_PARAMS = { :to => 'john.doe@example.com' }
7
+
8
+ def test_mail(*params)
9
+ Qu::Mailer.success!
10
+ mail(*params)
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qu-mailer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0rc1
5
+ prerelease: 5
6
+ platform: ruby
7
+ authors:
8
+ - Morton Jonuschat
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: actionmailer
16
+ requirement: &70221668759980 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70221668759980
25
+ - !ruby/object:Gem::Dependency
26
+ name: qu
27
+ requirement: &70221668758460 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.3
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70221668758460
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70221668757220 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 2.7.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70221668757220
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &70221668756480 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70221668756480
58
+ description: QuMailer is a Ruby on Rails 3.x plugin for sending asynchronous emails
59
+ with ActionMailer an Qu.
60
+ email:
61
+ - yabawock@gmail.com
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - lib/qu/mailer/message_decoy.rb
67
+ - lib/qu/mailer/version.rb
68
+ - lib/qu/mailer.rb
69
+ - lib/qu-mailer.rb
70
+ - lib/tasks/qu_mailer_tasks.rake
71
+ - MIT-LICENSE
72
+ - Rakefile
73
+ - README.md
74
+ - spec/dummy/db/test.sqlite3
75
+ - spec/dummy/log/test.log
76
+ - spec/qu_mailer_spec.rb
77
+ - spec/spec_helper.rb
78
+ - spec/support/action_mailer.rb
79
+ - spec/support/excluded_environments.rb
80
+ - spec/support/fake_qu.rb
81
+ - spec/support/test_mailer.rb
82
+ homepage: https://github.com/yabawock/qu-mailer
83
+ licenses: []
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ segments:
95
+ - 0
96
+ hash: 1170115688203683392
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>'
101
+ - !ruby/object:Gem::Version
102
+ version: 1.3.1
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 1.8.10
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Asynchronous email sending with ActionMailer and Qu
109
+ test_files:
110
+ - spec/dummy/db/test.sqlite3
111
+ - spec/dummy/log/test.log
112
+ - spec/qu_mailer_spec.rb
113
+ - spec/spec_helper.rb
114
+ - spec/support/action_mailer.rb
115
+ - spec/support/excluded_environments.rb
116
+ - spec/support/fake_qu.rb
117
+ - spec/support/test_mailer.rb