mandrill_queue 0.1.1

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.
@@ -0,0 +1,140 @@
1
+ require 'mandrill_queue/worker'
2
+ require 'mandrill_queue/variables'
3
+ require 'mandrill_queue/errors'
4
+ require 'mandrill_queue/message/recipients'
5
+ require 'mandrill_queue/message/recipient/metadata'
6
+ require 'mandrill_queue/message/merge_vars'
7
+ require 'mandrill_queue/message/attachments'
8
+ require 'mandrill_queue/message/images'
9
+
10
+ module MandrillQueue
11
+ module Message
12
+ class Internal
13
+ Variables::DSL.include_as(self, :global_merge_vars)
14
+ Variables::DSL.include_as(self, :metadata)
15
+
16
+ include Recipients::DSL
17
+ include MergeVars::DSL
18
+ include RecipientMetadata::DSL
19
+ include Attachments::DSL
20
+ include Images::DSL
21
+
22
+ ACCESSORS = [
23
+ :html, :text, :from_email, :from_name, :subject,
24
+ :headers, :important, :track_opens, :track_clicks, :auto_text, :auto_html,
25
+ :inline_css, :url_strip_qs, :preserve_recipients, :view_content_link,
26
+ :bcc_address, :tracking_domain, :signing_domain, :return_path_domain,
27
+ :merge, :tags, :subaccount, :google_analytics_domain,
28
+ :google_analytics_campaign
29
+ ]
30
+
31
+ EXTERNAL_ACCESSORS = [
32
+ :global_merge_vars, :merge_vars, :recipient_metadata,
33
+ :metadata, :attachments, :images
34
+ ]
35
+
36
+ def initialize(values = nil)
37
+ set!(values) unless values.nil?
38
+ end
39
+
40
+ ACCESSORS.each do |method|
41
+ define_method method do |*args|
42
+ var_sym = "@#{method}".to_sym
43
+ if args.count > 0
44
+ instance_variable_set(var_sym, args.first)
45
+ args.first
46
+ else
47
+ instance_variable_get(var_sym)
48
+ end
49
+ end
50
+ end
51
+
52
+ alias_method :dsl, :instance_eval
53
+
54
+ def nillify!
55
+ transform_accessors! { |k| nil }
56
+
57
+ EXTERNAL_ACCESSORS.each do |key|
58
+ instance_variable_set("@_#{key}", nil)
59
+ end
60
+
61
+ @_recipients = nil
62
+ self
63
+ end
64
+
65
+ def set!(values)
66
+ nillify!
67
+ values.symbolize_keys!
68
+ transform_accessors! { |k| values[k] }
69
+
70
+ EXTERNAL_ACCESSORS.each do |key|
71
+ send(key).set!(values[key]) unless values[key].nil?
72
+ end
73
+
74
+ [:to, :cc, :bcc].each do |key|
75
+ recipients.set!(values[key], key) if values[key]
76
+ end
77
+ end
78
+
79
+ def content_message?
80
+ !html.blank? || !text.blank?
81
+ end
82
+
83
+ def validate(errors)
84
+ errors.push([:message, "Please specify at least one recipient."]) if to.empty?
85
+
86
+ EXTERNAL_ACCESSORS.each do |key|
87
+ sym = "@_#{key}"
88
+ val = instance_variable_get(sym)
89
+ val.validate(errors) unless val.nil? || !val.respond_to?(:validate)
90
+ end
91
+
92
+ recipients.validate(errors)
93
+ end
94
+
95
+ def load_attachments!
96
+ @_attachments.load_all unless @_attachments.nil?
97
+ @_images.load_all unless @_images.nil?
98
+ self
99
+ end
100
+
101
+ def to_json(options = {})
102
+ to_hash(options).to_json
103
+ end
104
+
105
+ def to_hash(options = {})
106
+ hash = {}
107
+ hash[:to] = recipients.to_a(options) if @_recipients
108
+
109
+ ACCESSORS.each do |key|
110
+ value = instance_variable_get("@#{key}")
111
+ next if value.nil? && !options[:include_nils]
112
+ hash[key] = value.respond_to?(:to_hash) ? value.to_hash : value
113
+ end
114
+
115
+ EXTERNAL_ACCESSORS.each do |key|
116
+ sym = "@_#{key}".to_sym
117
+ var = instance_variable_get(sym)
118
+ if options[:include_nils] || !var.nil?
119
+ if var.is_a?(Variables::Internal)
120
+ hash[key] = var.to_key_value_array(options)
121
+ else
122
+ hash[key] = (var.to_hash(options) rescue var.to_a(options) rescue var)
123
+ end
124
+ end
125
+ end
126
+
127
+ hash
128
+ end
129
+
130
+ protected
131
+
132
+ def transform_accessors!
133
+ ACCESSORS.each do |key|
134
+ sym = "@#{key}".to_sym
135
+ instance_variable_set(sym, yield(key))
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,20 @@
1
+ require "rails"
2
+ require "abstract_controller/railties/routes_helpers"
3
+
4
+ module MandrillQueue
5
+ class Railtie < Rails::Railtie # :nodoc:
6
+ config.eager_load_namespaces << MandrillQueue
7
+
8
+ initializer "mandrill_queue.initialize" do |app|
9
+ ActiveSupport.on_load(:mandrill_queue) do
10
+ include AbstractController::UrlFor
11
+ extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
12
+ include app.routes.mounted_helpers
13
+
14
+ unless app.routes.default_url_options.has_key?(:host)
15
+ app.routes.default_url_options = app.config.action_mailer.default_url_options
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,99 @@
1
+ module MandrillQueue
2
+ module Variables
3
+ # Define DSL for inclusion in remote classes
4
+ module DSL
5
+ def self.include_as(base, name)
6
+ base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
7
+ def #{name}(values = nil, &block)
8
+ @_#{name} ||= Variables::Internal.new
9
+ @_#{name}.merge!(values) if values.is_a?(Hash)
10
+ @_#{name}.dsl(&block) if block_given?
11
+ block_given? ? self : @_#{name}
12
+ end
13
+ RUBY
14
+ end
15
+
16
+ def self.included(base)
17
+ include_as(base, :variables)
18
+ end
19
+ end
20
+
21
+ class Internal
22
+ def initialize(values = nil, &block)
23
+ @_variables = values if values.is_a?(Hash)
24
+ @_variables ||= {}
25
+ dsl(&block) if block_given?
26
+ end
27
+
28
+ alias_method :dsl, :instance_exec
29
+
30
+ def respond_to?(method)
31
+ super || @_variables.has_key?(method)
32
+ end
33
+
34
+ def to_hash(options = {})
35
+ if options.has_key?(:include_nils) && options[:include_nils]
36
+ @_variables
37
+ else
38
+ @_variables.reject { |k, v| v.nil? }
39
+ end
40
+ end
41
+
42
+ def to_key_value_array(options = {})
43
+ options[:name_key] ||= :name
44
+ options[:content_key] ||= :content
45
+
46
+ result = []
47
+ @_variables.each do |k, v|
48
+ if !v.nil? || options[:include_nils]
49
+ result.push({options[:name_key] => k.to_s, options[:content_key] => v})
50
+ end
51
+ end unless @_variables.nil?
52
+ result
53
+ end
54
+
55
+ def [](key)
56
+ @_variables[key]
57
+ end
58
+
59
+ def []=(key, value)
60
+ @_variables[key.to_sym] = value
61
+ end
62
+
63
+ def set!(hash, options = {})
64
+ case hash
65
+ when Hash
66
+ @_variables = hash.symbolize_keys
67
+ when Array
68
+ options[:name_key] ||= :name
69
+ options[:content_key] ||= :content
70
+ @_variables = {}
71
+ hash.dup.each do |obj|
72
+ obj.symbolize_keys!
73
+ @_variables[obj[options[:name_key]].to_sym] = obj[options[:content_key]]
74
+ end
75
+ end
76
+ self
77
+ end
78
+
79
+ def merge!(hash)
80
+ @_variables.merge!(hash)
81
+ end
82
+
83
+ def method_missing(method, *args, &block)
84
+ if method.to_s.end_with?('=')
85
+ method = method.to_s.chomp('=').to_sym
86
+ end
87
+
88
+ if args.count > 0
89
+ @_variables[method] = args.first
90
+ self
91
+ else
92
+ raise VariableNotSetError, "#{method} has not been set." \
93
+ unless @_variables.has_key?(method)
94
+ @_variables[method]
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,3 @@
1
+ module MandrillQueue
2
+ VERSION = '0.1.1'
3
+ end
@@ -0,0 +1,21 @@
1
+ require 'pp'
2
+ require 'stringio'
3
+ require 'mandrill_queue/logging'
4
+
5
+ module MandrillQueue
6
+ module Hooks
7
+ extend Logging
8
+
9
+ def on_failure_logging(error, message)
10
+ s = StringIO.new
11
+ PP.pp(message, s)
12
+ s.rewind
13
+ logging.error <<-TXT.strip
14
+ #{'=' * 50}
15
+ An exception has occurred for the following message:\n#{pretty(message)}
16
+ TXT
17
+ logging.error(error)
18
+ logging.error('=' * 50)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ require 'mandrill_queue/mailer'
2
+ require 'mandrill_queue/worker/hooks'
3
+ require 'mandrill_queue/mandrill_api'
4
+ require 'mandrill_queue/logging'
5
+
6
+ module MandrillQueue
7
+ class Worker
8
+ include MandrillApi
9
+ extend Logging
10
+ extend Hooks
11
+
12
+ def ip_pool
13
+ "Default Pool"
14
+ end
15
+
16
+ def perform(data)
17
+ @_mailer = Mailer.new(data)
18
+ self.class.logging.debug("Got mailer data: #{self.class.pretty(@_mailer.to_hash)}")
19
+
20
+ message = @_mailer.message.load_attachments!.to_hash
21
+ template = @_mailer.template
22
+ send_at = @_mailer.send_at
23
+
24
+ if template.nil?
25
+ mandrill.messages.send(message, false, ip_pool, send_at)
26
+ else
27
+ content = @_mailer.content.to_key_value_array
28
+ mandrill.messages.send_template(template, content, message, ip_pool, send_at)
29
+ end
30
+ end
31
+
32
+ def self.perform(*args)
33
+ result = new.perform(*args)
34
+ rescue Mandrill::Error => e
35
+ logging.error("A mandrill error occurred: #{e.class} - #{e.message}")
36
+ raise
37
+ else
38
+ if !result.empty?
39
+ log_results(result)
40
+ else
41
+ logging.error("No messages sent!")
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,52 @@
1
+ require 'mandrill_queue/railtie' if defined?(Rails)
2
+ require 'mandrill_queue/core_ext'
3
+ require 'mandrill_queue/configuration'
4
+ require 'mandrill_queue/mailer'
5
+
6
+ module MandrillQueue
7
+ def self.configuration
8
+ @configuration ||= Configuration.new(defaults)
9
+ end
10
+
11
+ def self.configure
12
+ yield configuration
13
+ self
14
+ end
15
+
16
+ def self.defaults
17
+ {
18
+ message_defaults: {}
19
+ }
20
+ end
21
+
22
+ def self.resque
23
+ configuration.resque || ::Resque
24
+ end
25
+
26
+ # TODO: Support worker adapters
27
+ # def self.load_adapter(adapter)
28
+ # require "mandrill_queue/adapters/#{adapter}"
29
+ # "#{adapter.camelize}Adapter".constantize.new
30
+ # end
31
+
32
+ # def self.adapter
33
+ # @_adapter ||= begin
34
+ # unless adapter = configuration.adapter
35
+ # adapter = :resque if defined(::Resque)
36
+ # adapter = :sidekiq if defined(::Sidekiq)
37
+ # if adapter.nil?
38
+ # raise RuntimeError, <<-TXT.strip.tr("\t", '')
39
+ # Worker adapter was not configured and cannot be determined.
40
+ # Please include a worker gem in your Gemfile. Resque and Sidekiq are supported.
41
+ # TXT
42
+ # end
43
+ # end
44
+ # load_adapter(adapter)
45
+ # end
46
+ # end
47
+
48
+ def self.reset_config(&block)
49
+ @configuration = nil
50
+ configure(&block) if block_given?
51
+ end
52
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails'
2
+
3
+ module MandrillQueue
4
+ module Generators
5
+ class InitializerGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ desc "Creates a default MandrillQueue initializer."
9
+ def create_initializer_file
10
+ copy_file 'initializer.rb', "config/initializers/mandrill_queue.rb"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ MandrillQueue.configure do |config|
2
+ # Your Mandrill API key
3
+ # Only needed for the worker, so leave out if you run your worker
4
+ # externally to Rails.
5
+ # config.api_key = 'xxxxxx'
6
+
7
+ # Message defaults.
8
+ # A hash of application-wide default values for messages.
9
+ # These can be overriden by class level defaults and by method
10
+ # level defaults.
11
+ # e.g.
12
+ # {
13
+ # from_email: 'no-reply@example.com',
14
+ # preserve_recipients: false,
15
+ # global_merge_vars: {
16
+ # application_name: 'My super app!'
17
+ # }
18
+ # }
19
+ # config.message_defaults = {}
20
+
21
+ # MandrillQueue will call enqueue on this instead of Resque
22
+ # config.resque = MyOwnResque
23
+
24
+ # Allows you to use your own worker for processing the mandrill
25
+ # queue. This can be overriden at the class level.
26
+ # config.default_worker_class = MyWorker
27
+
28
+ # Allows you to override the queue name used to enqueue
29
+ # to resque. This can be overriden at the class level
30
+ # Defaults to :mailer
31
+ # config.default_queue = :another_queue
32
+
33
+ # Used to set the current logger. This can be any object
34
+ # that responds to debug, info, warn, error and fatal
35
+ # config.logger = MyLoggingClass
36
+ end
@@ -0,0 +1,23 @@
1
+ $:.unshift(File.expand_path('../', __FILE__))
2
+ # Generated by MandrillQueue gem
3
+ # Use this to have a light weight resque worker (no rails environment)
4
+ # which can be run as follows:
5
+ # QUEUES=mailer rake resque:work -r ./worker.rb
6
+
7
+ require 'bundler/setup'
8
+
9
+ require 'resque'
10
+ require 'resque/tasks'
11
+ require 'mono_logger' # or log4r or rails logger
12
+
13
+ # Require the class that actually does the work
14
+ require 'mandrill_queue/worker'
15
+
16
+ # You can load your rails initializer here:
17
+ # require 'config/initializer/mandrill_queue.rb
18
+ # or configure only what you need for the worker:
19
+ MandrillQueue.configure do |config|
20
+ config.api_key = ''# TODO: Mandrill api key
21
+
22
+ config.logger = MonoLogger.new(STDOUT) # or log4r or Logger or ...
23
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails'
2
+
3
+ module MandrillQueue
4
+ module Generators
5
+ class WorkerGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ desc "Creates an default worker entrypoint for rake resque:work -r ./worker.rb"
9
+ def create_worker_file
10
+ copy_file 'worker.rb', "./worker.rb"
11
+
12
+ puts 'Worker created! You can run it with the following command:'
13
+ puts 'cd worker; QUEUES=mailer rake resque:work -r ./worker.rb'
14
+ end
15
+ end
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,205 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mandrill_queue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stan Bondi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 4.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 4.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: mandrill-api
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - '='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.49
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.49
46
+ - !ruby/object:Gem::Dependency
47
+ name: mime-types
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: '1.25'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: '1.25'
62
+ - !ruby/object:Gem::Dependency
63
+ name: bundler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.3'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: timecop
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: factory_girl
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: faker
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ description: Use MailChimps Mandrill to send mailers through a background worker queue.
143
+ email:
144
+ - stan@fixate.it
145
+ executables: []
146
+ extensions: []
147
+ extra_rdoc_files: []
148
+ files:
149
+ - lib/mandrill_queue.rb
150
+ - lib/rails/generators/mandrill_queue/worker_generator.rb
151
+ - lib/rails/generators/mandrill_queue/initializer_generator.rb
152
+ - lib/rails/generators/mandrill_queue/templates/initializer.rb
153
+ - lib/rails/generators/mandrill_queue/templates/worker/worker.rb
154
+ - lib/mandrill_queue/mailer.rb
155
+ - lib/mandrill_queue/worker.rb
156
+ - lib/mandrill_queue/version.rb
157
+ - lib/mandrill_queue/core_ext.rb
158
+ - lib/mandrill_queue/errors.rb
159
+ - lib/mandrill_queue/variables.rb
160
+ - lib/mandrill_queue/logging.rb
161
+ - lib/mandrill_queue/railtie.rb
162
+ - lib/mandrill_queue/message/recipient/helpers.rb
163
+ - lib/mandrill_queue/message/recipient/metadata.rb
164
+ - lib/mandrill_queue/message/recipient/variable.rb
165
+ - lib/mandrill_queue/message/recipient/data.rb
166
+ - lib/mandrill_queue/message/attachments.rb
167
+ - lib/mandrill_queue/message/merge_vars.rb
168
+ - lib/mandrill_queue/message/images.rb
169
+ - lib/mandrill_queue/message/recipients.rb
170
+ - lib/mandrill_queue/mandrill_api.rb
171
+ - lib/mandrill_queue/worker/hooks.rb
172
+ - lib/mandrill_queue/configuration.rb
173
+ - lib/mandrill_queue/array_metadata.rb
174
+ - lib/mandrill_queue/message.rb
175
+ - Rakefile
176
+ - README.md
177
+ - Gemfile
178
+ - Guardfile
179
+ - LICENSE.txt
180
+ homepage: https://github.com/fixate/mandrill_queue/
181
+ licenses:
182
+ - MIT
183
+ post_install_message:
184
+ rdoc_options: []
185
+ require_paths:
186
+ - lib
187
+ required_ruby_version: !ruby/object:Gem::Requirement
188
+ none: false
189
+ requirements:
190
+ - - ! '>='
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ required_rubygems_version: !ruby/object:Gem::Requirement
194
+ none: false
195
+ requirements:
196
+ - - ! '>='
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ requirements: []
200
+ rubyforge_project:
201
+ rubygems_version: 1.8.23
202
+ signing_key:
203
+ specification_version: 3
204
+ summary: Use MailChimps Mandrill to send mailers through a background worker queue.
205
+ test_files: []