launch_control 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 21eb9c590a1ca3178bd2aaf43dd87ae47d72d04c
4
+ data.tar.gz: 89e70a81ac91e1987f59fb39b397d7fba2ea4bab
5
+ SHA512:
6
+ metadata.gz: d6bb6fd748e01b0b88f3919eaedbbdf0a5a303a80e7010c9344c598cd5e18d4e9a7db9ca1a613deea0d463e8c8e12ba3be694a5fd65dafd249beeeb4ebe2b8ac
7
+ data.tar.gz: 96d3b5e7c730749a5c3da5e2b3d18ba3b4aaf7376902ec2e4191adde50f6bb4b9c558c80efc6f8659b533c9c277d85d86b4ad86c91386acb9fcc2bcef958ea9b
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in launch_control.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Chris Teague
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # LaunchControl
2
+
3
+ LaunchControl eases and helps improve the integrity of mail delivered via Mandrill templates.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'launch_control'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install launch_control
20
+
21
+ Within your application (for a Rails app, typically /config/initializers/launch_control.rb), setup your Mandrill API key you wish to use:
22
+
23
+ LaunchControl.configure do |config|
24
+ config.mandrill_api_key = 'your_key_here'
25
+ end
26
+
27
+ ## Usage
28
+
29
+ To start using Launch Control, you first need to create a contract class:
30
+
31
+ class ThankyouEmail < LaunchControl::MandrillContract
32
+ def template
33
+ 'thank-you'
34
+ end
35
+
36
+ def validations
37
+ {
38
+ first_name: 'string',
39
+ last_name: 'string'
40
+ }
41
+ end
42
+ end
43
+
44
+ Here we define which Mandrill template id we are going to use, and which global merge variables we require to use this template safely. Validations use the [Hash Validator](https://github.com/jamesbrooks/hash_validator) gem, check it out for an idea of what's possible.
45
+
46
+ Now to send an email, we can use our MandrillContract subclass and simply push in all the details required as a hash:
47
+
48
+ mailer = ThankyouEmail.new
49
+ mailer.deliver(to: 'team@lotus.com', subject: 'Bring it home safely', first_name: 'Pastor', last_name: 'Maldonado')
50
+ => true
51
+
52
+ Now if you try and deliver this without the appropriate content, you'll be pulled up on it:
53
+
54
+ mailer.deliver(to: 'team@ferarri.com', subject: 'I know what I\'m doing', first_name: 'Kimi')
55
+ => false
56
+
57
+ mailer.errors
58
+ => {:last_name=>"string required"}
59
+
60
+ ## Development
61
+
62
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
63
+
64
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
65
+
66
+ ## Contributing
67
+
68
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/launch_control.
69
+
70
+
71
+ ## License
72
+
73
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
74
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "launch_control"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'launch_control/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "launch_control"
8
+ spec.version = LaunchControl::VERSION
9
+ spec.authors = ["Chris Teague"]
10
+ spec.email = ["chris@cteague.com.au"]
11
+
12
+ spec.summary = %q{Ensure that emails delivered to Mandrill meet a specified contract.}
13
+ spec.homepage = "https://flybeacon.com/"
14
+ spec.license = "MIT"
15
+
16
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
17
+ # delete this section to allow pushing this gem to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
22
+ end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_dependency "mandrill-api", '~> 1.0', ">= 1.0.53"
30
+ spec.add_dependency "hash_validator", '~> 0.4', ">= 0.4.0"
31
+ spec.add_dependency "activesupport", ">= 3.2.13"
32
+
33
+ spec.add_development_dependency "bundler", ">= 1.10"
34
+ spec.add_development_dependency "rake", ">= 10.0"
35
+ spec.add_development_dependency "rspec", '~> 3.2', ">= 3.2.0"
36
+ spec.add_development_dependency "pry", '~> 0.9', ">= 0.9.12"
37
+ spec.add_development_dependency "webmock"
38
+ spec.add_development_dependency "simplecov", '~> 0.10', ">= 0.10.0"
39
+ end
@@ -0,0 +1,70 @@
1
+ module LaunchControl
2
+
3
+ require 'hash_validator'
4
+
5
+ class MandrillContract
6
+
7
+ attr_accessor :errors
8
+
9
+ #
10
+ # Override this with any custom validations you wish
11
+ # to perform on your mail object before delivering.
12
+ #
13
+ def validations
14
+ {}
15
+ end
16
+
17
+ #
18
+ # Override this with your template id from Mandrill.
19
+ #
20
+ def template
21
+ raise 'You must define a Mandrill template to use'
22
+ end
23
+
24
+ #
25
+ # Override these to control how your validations and
26
+ # merge variables get integrated with Launch Control
27
+ # defaults. For example:
28
+ #
29
+ # def merged_options(options)
30
+ # options.merge(to_json)
31
+ # end
32
+ #
33
+ # This allows you to wrap any custom merge vars into
34
+ # a to_json method for a cleaner interaction.
35
+ #
36
+ def merged_contract
37
+ default_email_contract.merge!(validations)
38
+ end
39
+
40
+ def merged_options(options)
41
+ options
42
+ end
43
+
44
+
45
+ def deliver(options)
46
+ options = merged_options(options)
47
+ launch = LaunchControl::Mailer.new(template, options)
48
+ valid?(options) && launch.valid? && launch.deliver
49
+ end
50
+
51
+ def default_email_contract
52
+ {
53
+ to: lambda { |to| [Array,String,Hash].include?(to.class) },
54
+ subject: 'string'
55
+ }
56
+ end
57
+
58
+ def valid?(options)
59
+ validator = HashValidator.validate(options, merged_contract)
60
+ if validator.valid?
61
+ true
62
+ else
63
+ @errors = validator.errors
64
+ false
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,3 @@
1
+ module LaunchControl
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,165 @@
1
+ require "launch_control/version"
2
+ require "launch_control/mandrill_contract"
3
+ require 'mandrill'
4
+ require 'pry'
5
+ require 'active_support/core_ext/hash/keys'
6
+ require 'active_support/core_ext/object/blank'
7
+
8
+ module LaunchControl
9
+
10
+ #
11
+ # To start using Launch Control, you first need to create a contract class, i.e.:
12
+ #
13
+ # class ThankyouEmail < LaunchControl::MandrillContract
14
+ #
15
+ # def template
16
+ # 'thank-you'
17
+ # end
18
+ #
19
+ # def validations
20
+ # {
21
+ # first_name: 'string',
22
+ # last_name: 'string'
23
+ # }
24
+ # end
25
+ # end
26
+ #
27
+ # Define global merge vars to integrate with your Mandrill template:
28
+ #
29
+ # mailer = ThankyouEmail.new
30
+ # mailer.deliver(to: 'team@lotus.com', subject: 'Bring it home safely', first_name: 'Pastor', last_name: 'Maldonado')
31
+ # => true
32
+ #
33
+ # Now if you try and deliver this without the appropriate content, you'll be pulled up on it:
34
+ #
35
+ # mailer.deliver(to: 'team@ferarri.com', subject: 'I know what I\'m doing', first_name: 'Kimi')
36
+ # => false
37
+ # mailer.errors
38
+ # => {:last_name=>"string required"}
39
+ #
40
+ #
41
+ class Mailer
42
+
43
+ attr_accessor :template_id, :cc, :bcc, :to, :from_name, :from_email,
44
+ :reply_to, :subject, :merge_vars
45
+
46
+ def initialize(template_id, options)
47
+ options = options.dup
48
+
49
+ raise 'Please configure your Mandrill API key before trying to deliver emails.' if LaunchControl.configuration.mandrill_api_key.nil?
50
+
51
+ @template_id = template_id
52
+ @to = options.delete(:to)
53
+ @cc = options.delete(:cc)
54
+ @bcc = options.delete(:bcc)
55
+ @from_name = options.delete(:from_name)
56
+ @from_email = options.delete(:from_email)
57
+ @reply_to = options.delete(:reply_to)
58
+ @subject = options.delete(:subject)
59
+ @merge_vars = options
60
+ end
61
+
62
+ def mandrill
63
+ @mandrill ||= Mandrill::API.new(LaunchControl.configuration.mandrill_api_key)
64
+ end
65
+
66
+ def deliver
67
+ if valid?
68
+ response = mandrill.messages.send_template(@template_id, [], message, false)
69
+ response[0]["status"] == "sent"
70
+ end
71
+ end
72
+
73
+ def valid?
74
+ !!(@to && @subject && @template_id)
75
+ end
76
+
77
+ private
78
+
79
+ def message
80
+ {
81
+ "headers" => {
82
+ "Reply-To" => @reply_to
83
+ },
84
+ "merge_language" => "handlebars",
85
+ "to" => build_addresses,
86
+ "subject" => @subject,
87
+ "from_name" => @from_name,
88
+ "from_email" => @from_email,
89
+ "global_merge_vars" => build_merge_vars
90
+ }
91
+ end
92
+
93
+ def build_addresses
94
+ [build_to, build_cc, build_bcc].reject(&:nil?).flatten
95
+ end
96
+
97
+ #
98
+ # Defines build_to, build_cc & build_bcc methods.
99
+ #
100
+ # These can accept either singular or array collections
101
+ # of Strings or Hashes.
102
+ #
103
+ # Some examples of possible to, cc & bcc values:
104
+ #
105
+ # 'test@test.com'
106
+ # { email: 'test@test.com', name: 'Test' }
107
+ # ['test@test.com', 'another@email.com']
108
+ #
109
+ [:to, :cc, :bcc].each do |i|
110
+ define_method("build_#{i}") do |address=nil|
111
+ current_address = address || instance_variable_get("@#{i}")
112
+ case current_address
113
+ when Array
114
+ current_address.collect do |addr|
115
+ send("build_#{i}".to_sym, addr)
116
+ end.flatten
117
+ when Hash
118
+ [current_address.stringify_keys.merge({"type" => i.to_s })]
119
+ when String
120
+ [{ "email" => "#{current_address}", "type" => i.to_s }]
121
+ end
122
+ end
123
+ end
124
+
125
+
126
+ def build_merge_vars
127
+ unless @merge_vars.empty?
128
+ @merge_vars.collect { |key, value| { 'name' => key.to_s, 'content' => value } }
129
+ else
130
+ []
131
+ end
132
+ end
133
+
134
+ end
135
+
136
+ #
137
+ # Allow external configuration of Mandrill API Key &
138
+ # potentially more in future.
139
+ #
140
+ # e.g.
141
+ #
142
+ # LaunchControl.configure do |config|
143
+ # config.mandrill_api_key = 'your_key_here'
144
+ # end
145
+ #
146
+ # Reference: https://robots.thoughtbot.com/mygem-configure-block
147
+ #
148
+ class << self
149
+ attr_accessor :configuration
150
+ end
151
+
152
+ def self.configure
153
+ self.configuration ||= Configuration.new
154
+ yield(configuration)
155
+ end
156
+
157
+ class Configuration
158
+ attr_accessor :mandrill_api_key
159
+
160
+ def initialize
161
+ @mandrill_api_key = nil
162
+ end
163
+ end
164
+
165
+ end
metadata ADDED
@@ -0,0 +1,214 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: launch_control
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Teague
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mandrill-api
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ - - '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.53
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
30
+ - - '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.53
33
+ - !ruby/object:Gem::Dependency
34
+ name: hash_validator
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: '0.4'
40
+ - - '>='
41
+ - !ruby/object:Gem::Version
42
+ version: 0.4.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ~>
48
+ - !ruby/object:Gem::Version
49
+ version: '0.4'
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: 0.4.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: activesupport
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - '>='
58
+ - !ruby/object:Gem::Version
59
+ version: 3.2.13
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - '>='
65
+ - !ruby/object:Gem::Version
66
+ version: 3.2.13
67
+ - !ruby/object:Gem::Dependency
68
+ name: bundler
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '1.10'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '1.10'
81
+ - !ruby/object:Gem::Dependency
82
+ name: rake
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '10.0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '10.0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: rspec
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '3.2'
102
+ - - '>='
103
+ - !ruby/object:Gem::Version
104
+ version: 3.2.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ~>
110
+ - !ruby/object:Gem::Version
111
+ version: '3.2'
112
+ - - '>='
113
+ - !ruby/object:Gem::Version
114
+ version: 3.2.0
115
+ - !ruby/object:Gem::Dependency
116
+ name: pry
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ~>
120
+ - !ruby/object:Gem::Version
121
+ version: '0.9'
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: 0.9.12
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: '0.9'
132
+ - - '>='
133
+ - !ruby/object:Gem::Version
134
+ version: 0.9.12
135
+ - !ruby/object:Gem::Dependency
136
+ name: webmock
137
+ requirement: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ type: :development
143
+ prerelease: false
144
+ version_requirements: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ - !ruby/object:Gem::Dependency
150
+ name: simplecov
151
+ requirement: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ~>
154
+ - !ruby/object:Gem::Version
155
+ version: '0.10'
156
+ - - '>='
157
+ - !ruby/object:Gem::Version
158
+ version: 0.10.0
159
+ type: :development
160
+ prerelease: false
161
+ version_requirements: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ~>
164
+ - !ruby/object:Gem::Version
165
+ version: '0.10'
166
+ - - '>='
167
+ - !ruby/object:Gem::Version
168
+ version: 0.10.0
169
+ description:
170
+ email:
171
+ - chris@cteague.com.au
172
+ executables: []
173
+ extensions: []
174
+ extra_rdoc_files: []
175
+ files:
176
+ - .gitignore
177
+ - .rspec
178
+ - .travis.yml
179
+ - Gemfile
180
+ - LICENSE.txt
181
+ - README.md
182
+ - Rakefile
183
+ - bin/console
184
+ - bin/setup
185
+ - launch_control.gemspec
186
+ - lib/launch_control.rb
187
+ - lib/launch_control/mandrill_contract.rb
188
+ - lib/launch_control/version.rb
189
+ homepage: https://flybeacon.com/
190
+ licenses:
191
+ - MIT
192
+ metadata:
193
+ allowed_push_host: https://rubygems.org
194
+ post_install_message:
195
+ rdoc_options: []
196
+ require_paths:
197
+ - lib
198
+ required_ruby_version: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - '>='
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ required_rubygems_version: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - '>='
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ requirements: []
209
+ rubyforge_project:
210
+ rubygems_version: 2.4.5
211
+ signing_key:
212
+ specification_version: 4
213
+ summary: Ensure that emails delivered to Mandrill meet a specified contract.
214
+ test_files: []