Permalink
Browse files

Initial commit.

  • Loading branch information...
michaelklishin committed Jun 21, 2008
0 parents commit d3098fc864b8d9437955347698f2bbf78ff5eeee
@@ -0,0 +1,4 @@
+.gitignore
+pkg/*
+log/*
+TAGS
20 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 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
@@ -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 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.
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Oops, something went wrong.

0 comments on commit d3098fc

Please sign in to comment.