Navigation Menu

Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelklishin committed Jun 21, 2008
0 parents commit d3098fc
Show file tree
Hide file tree
Showing 24 changed files with 656 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
.gitignore
pkg/*
log/*
TAGS
20 changes: 20 additions & 0 deletions LICENSE
@@ -0,0 +1,20 @@
Copyright (c) 2008 Michael Klishin

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 changes: 39 additions & 0 deletions README
@@ -0,0 +1,39 @@
merb_mail_queue
===============

A plugin for the Merb framework that provides mail queueing functionality.
Instead of sending emails right away, this plugin queues them into database
table and provides simple processor that loads queue and does send out in the
background.

Setup
===============

Add dependencies in your init file like this:

dependencies "merb-mailer", "merb_mail_queue"


Set up configuration and load plugin in after_app_loads hook. This plugin has
two configuration options: adapter name (only ActiveRecord is supported at the moment)
and mail queue job model class name. So it may look like this in the end.

Queue processor assumed to use your application mailer configuration.

Merb::BootLoader.after_app_loads do
Merb::Plugins.config[:merb_mail_queue] = {
:mail_queue_job_model_class_name => "MailQueueJob",
:adapter => :activerecord
}

Merb::MailQueue.load_plugin!

Merb::Mailer.config = {
:host => 'mail.your-domain.com',
:port => '25',
:user => 'webmaster',
:pass => 'supersecret',
:auth => :plain, # :plain, :login, :cram_md5, the default is no auth
:domain => "your-domain.com" # the HELO domain provided by the client to the server
}
end
59 changes: 59 additions & 0 deletions Rakefile
@@ -0,0 +1,59 @@
require 'rubygems'
require 'spec/rake/spectask'
require 'rake/gempackagetask'
require 'merb-core/test/tasks/spectasks'
require 'rubygems/specification'
require 'date'
require 'merb-core/version'
require 'merb-core/tasks/merb_rake_helper'

NAME = "merb_mail_queue"
GEM_VERSION = "0.0.1"
AUTHOR = "Michael Klishin"
EMAIL = "michael@novemberain.com"
HOMEPAGE = "http://merbivore.com/"
SUMMARY = "Merb plugin that provides mail queueing: asynchronous mail sending. Based on merb-mailer."

spec = Gem::Specification.new do |s|
s.rubyforge_project = 'merb'
s.name = NAME
s.version = GEM_VERSION
s.platform = Gem::Platform::RUBY
s.has_rdoc = true
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
s.summary = SUMMARY
s.description = s.summary
s.author = AUTHOR
s.email = EMAIL
s.homepage = HOMEPAGE
s.add_dependency('merb-core', '>= 0.9.4')
s.add_dependency('merb-mailer', '>= 0.9.4')
s.require_path = 'lib'
s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")

end

Rake::GemPackageTask.new(spec) do |pkg|
pkg.gem_spec = spec
end

desc "install the plugin locally"
task :install => [:package] do
sh %{#{sudo} gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION} --no-update-sources}
end

desc "create a gemspec file"
task :make_spec do
File.open("#{NAME}.gemspec", "w") do |file|
file.puts spec.to_ruby
end
end

namespace :jruby do

desc "Run :package and install the resulting .gem with jruby"
task :install => :package do
sh %{#{sudo} jruby -S gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION}.gem --no-rdoc --no-ri}
end

end
10 changes: 10 additions & 0 deletions TODO
@@ -0,0 +1,10 @@
TODO:

* Better specs for multiple recipients.
* Add DataMapper adapter.
* Add Sequel adapter.
* Extract Adapters load/registration API into a separate gem.
* Better spec helpers organization.
* Add generators for models, migrations.
* Remove duplication with merb-mailer.
* Simplify the plugin wherever possible.
17 changes: 17 additions & 0 deletions lib/merb_mail_queue.rb
@@ -0,0 +1,17 @@
# make sure we're running inside Merb
if defined?(Merb::Plugins)
require "merb-mailer"

require File.dirname(__FILE__) / "merb_mail_queue" / "initializer"
require File.dirname(__FILE__) / "merb_mail_queue" / "mail_queue_mixin"
require File.dirname(__FILE__) / "merb_mail_queue" / "processor"

adapter_path = File.dirname(__FILE__) / "merb_mail_queue" / "adapters"
Merb::MailQueue.register_adapter :activerecord, "#{adapter_path}/activerecord"

Merb::Plugins.config[:merb_mail_queue] = {
:mail_queue_job_model_class_name => "MailQueueJob"
}

Merb::Plugins.add_rakefiles "merb_mail_queue/merbtasks"
end
16 changes: 16 additions & 0 deletions lib/merb_mail_queue/adapters/activerecord/init.rb
@@ -0,0 +1,16 @@
require "activerecord"

module Merb
module MailQueue
module Adapters
module ActiveRecord

end
end
end
end

path = File.dirname(__FILE__)
require path / "map"

Merb::MailQueue.mail_queue_job_model_class.send(:include, Merb::MailQueue::Adapters::ActiveRecord::Map)
31 changes: 31 additions & 0 deletions lib/merb_mail_queue/adapters/activerecord/map.rb
@@ -0,0 +1,31 @@
module Merb
module MailQueue
module Adapters
module ActiveRecord
module Map

def self.included(base)
base.send(:include, InstanceMethods)
base.send(:extend, ClassMethods)
end

module InstanceMethods
end

module ClassMethods
def load_queue(*args)
find(:all, *args)
end

def queue(from, to, subject, body)
[to].flatten.each do |recepient|
create(:to => recepient, :from => from, :subject => subject, :body => body)
end
end
end # ClassMethods

end # Map
end # ActiveRecord
end # Adapters
end # MailQueue
end # Merb
65 changes: 65 additions & 0 deletions lib/merb_mail_queue/initializer.rb
@@ -0,0 +1,65 @@
module Merb
module Plugins
class AdapterIsNotRegistred < StandardError
def initialize(adapter)
super("Adapter #{adapter} is not registred")
end
end

class NoAdapterSpecified < StandardError
end
end

module MailQueue

def self.config
Merb::Plugins.config[:merb_mail_queue]
end

def self.mail_queue_job_model_class
Object.full_const_get(Merb::Plugins.config[:merb_mail_queue][:mail_queue_job_model_class_name])
end

# Clears the currently registered adapter list.
def self.clear_adapter_list!
@_adapters = nil
end

# Registers an adapter.
# @param [Symbol] name is the name of the adapter. Supported adapters are :datamapper and :activerecord
# @param [String] path is the path to the adapter. The adapter path _directory_ should include an init.rb file
# @param [Hash] opts an options hash
def self.register_adapter(name, path, opts = {})
adapters[name.to_sym] = opts.merge!(:path => path)
end

# @return [Hash] A hash of the adapters.
def self.adapters
@_adapters ||= Hash.new{|h,k| h[k] = {}}
end

# Loads the adapter provided, or if not provided, the adapter set in the slices config
# @param [Symbol | String] adapter The name of the adapter to load. This must be registered
# @raise [RuntimeError] Raises an error if the adapter is not registered.
def self.load_adapter!(adapter = nil)
adapter ||= self.config[:adapter] || Merb.orm_generator_scope
raise Merb::Plugins::NoAdapterSpecified if adapter.nil? || adapter.blank?

# Check that the adapter is registered
raise Merb::Plugins::AdapterIsNotRegistred.new(adapter) unless adapters.keys.include?(adapter.to_sym)

if Merb.env?(:test)
load adapters[adapter.to_sym][:path] / "init.rb"
else
require adapters[adapter.to_sym][:path] / "init"
end
end

def self.load_plugin!
Merb::Controller.send(:include, Merb::MailQueue::MailQueueMixin)
Merb::MailController.send(:include, Merb::MailQueue::DispatchAndQueueMixin)
Merb::MailQueue.load_adapter!(Merb::Plugins.config[:merb_mail_queue][:adapter])
end

end
end
37 changes: 37 additions & 0 deletions lib/merb_mail_queue/mail_queue_mixin.rb
@@ -0,0 +1,37 @@
module Merb
module MailQueue
module MailQueueMixin

def queue_mail(klass, method, mail_params, send_params = nil)
klass.new(send_params || params, self).dispatch_and_queue(method, mail_params)
end

end
end
end

module Merb
module MailQueue
module DispatchAndQueueMixin

def dispatch_and_queue(method, mail_params)
@mailer = self.class._mailer_klass.new(mail_params)
@mail = @mailer.mail
@method = method

# dispatch and render use params[:action], so set it
self.action_name = method

body = _dispatch method
if !@mail.html.blank? || !@mail.text.blank?
body = @mail.html || @mail.text
Merb::MailQueue.mail_queue_job_model_class.queue(@mail.from, @mail.to.first, @mail.subject.first, body)
Merb.logger.info "Email queued: to #{@mail.to} about #{@mail.subject}"
else
Merb.logger.info "#{method} was not sent because nothing was rendered for it"
end
end

end
end
end
6 changes: 6 additions & 0 deletions lib/merb_mail_queue/merbtasks.rb
@@ -0,0 +1,6 @@
namespace :merb_mail_queue do
desc "Do something for merb_mail_queue"
task :default do
puts "merb_mail_queue doesn't do anything"
end
end
15 changes: 15 additions & 0 deletions lib/merb_mail_queue/processor.rb
@@ -0,0 +1,15 @@
module Merb
module MailQueue
class Processor

def process(queue = Merb::MailQueue.mail_queue_job_model_class.load_queue)
queue.each do |job|
Merb::Mailer.new(job.attributes).deliver!

job.destroy
end
end

end
end
end
23 changes: 23 additions & 0 deletions merb_mail_queue.gemspec
@@ -0,0 +1,23 @@
Gem::Specification.new do |s|
s.name = %q{merb_mail_queue}
s.version = "0.0.1"

s.specification_version = 2 if s.respond_to? :specification_version=

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Michael Klishin"]
s.date = %q{2008-06-21}
s.description = %q{Merb plugin that provides mail queueing: asynchronous mail sending. Based on merb-mailer.}
s.email = %q{michael@novemberain.com}
s.extra_rdoc_files = ["README", "LICENSE", "TODO"]
s.files = ["LICENSE", "README", "Rakefile", "TODO", "lib/merb_mail_queue", "lib/merb_mail_queue/adapters", "lib/merb_mail_queue/adapters/activerecord", "lib/merb_mail_queue/adapters/activerecord/init.rb", "lib/merb_mail_queue/adapters/activerecord/map.rb", "lib/merb_mail_queue/initializer.rb", "lib/merb_mail_queue/mail_queue_mixin.rb", "lib/merb_mail_queue/merbtasks.rb", "lib/merb_mail_queue/processor.rb", "lib/merb_mail_queue.rb", "spec/active_record_helper.rb", "spec/default_plugin_configuration_spec.rb", "spec/mail_queue_mixin_spec.rb", "spec/mail_queue_processor_spec.rb", "spec/mailers", "spec/mailers/views", "spec/mailers/views/delayed_mail_controller", "spec/mailers/views/delayed_mail_controller/first.html.erb", "spec/mailers/views/delayed_mail_controller/second.html.erb", "spec/merb_mail_queue_spec.rb", "spec/models", "spec/models/ar_mail_queue_job_spec.rb", "spec/orm_adapter_registration_spec.rb", "spec/spec.opts", "spec/spec_helper.rb"]
s.has_rdoc = true
s.homepage = %q{http://merbivore.com/}
s.require_paths = ["lib"]
s.rubyforge_project = %q{merb}
s.rubygems_version = %q{1.1.1}
s.summary = %q{Merb plugin that provides mail queueing: asynchronous mail sending. Based on merb-mailer.}

s.add_dependency(%q<merb-core>, [">= 0.9.4"])
s.add_dependency(%q<merb-mailer>, [">= 0.9.4"])
end

0 comments on commit d3098fc

Please sign in to comment.