crosby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7b6644351cbd94255b116edf49999a4aa7f8a202
4
+ data.tar.gz: d206eadba0406bd3d0df0f7c07f7d819ec6eb38a
5
+ SHA512:
6
+ metadata.gz: 4a8bbab03e19b11417d517d44b76d7fa59c7a09d4d70fe35dc9ebb660538842d0ad8d431589b7296e0c431fb4575f174e314e16ffd46a41d91c82c393d3a6b90
7
+ data.tar.gz: 44460e785fa692c1249d98df48c912bd50a8b55f4fe6773d00c0dba1ddff5aeed78545110ffacf60c97af8995c47bd659d275010c34d847b4a2bd58ee7092e5d
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "pry"
4
+
5
+ # Specify your gem"s dependencies in crosby.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Dan Matthews
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # Crosby
2
+
3
+ Allows for quality checks on `ActionMailer` emails when migrating to new systems.
4
+
5
+ http://en.wikipedia.org/wiki/Philip_B._Crosby
6
+
7
+ ```
8
+ Crosby's response to the quality crisis was the principle of
9
+ "doing it right the first time" (DIRFT). He also included four major principles:
10
+
11
+ The definition of quality is conformance to requirements
12
+ (requirements meaning both the product and the customer's requirements)
13
+ The system of quality is prevention
14
+ The performance standard is zero defects (relative to requirements)
15
+ The measurement of quality is the price of nonconformance
16
+ ```
17
+
18
+ This is a work in progress which came out of a need to compare emails generated
19
+ on our 'nextjenn' platform to emails generated in our legacy codebase.
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem "crosby"
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install crosby
36
+
37
+ ## Configuration
38
+
39
+ Crosby has 2 configurable values, `app_name` and `export_path` with the
40
+ following defaults:
41
+
42
+ ```ruby
43
+ Crosby.config
44
+ # => { :app_name => "6f292f17", :export_path => "tmp/crosby" }
45
+ ```
46
+
47
+ NOTE: The value of `app_name` is randomized and will not stay consistent across
48
+ application loads unless specifically set. Config options can be set via a
49
+ block.
50
+
51
+ ```ruby
52
+ Crosby.config do |c|
53
+ c.app_name = "ExampleApp"
54
+ c.export_path = "../crosby_files"
55
+ end
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ### Basic Usage
61
+
62
+ Crosby exports a slightly curated version of `Mail::Message` objects produced
63
+ by `ActionMailer` subclasses to a `.crosby` file. The class responsible for
64
+ producing this file is `Crosby::Exporter`.
65
+
66
+ ```ruby
67
+ exporter = Crosby::Exporter.new(
68
+ MailerClass, :method, 'a-unique-id'[, arg1[, arg2[, ...]]]
69
+ )
70
+
71
+ exporter.export
72
+ ```
73
+
74
+ Also available is the `Crosby::Exporter#to_s` method which will return the
75
+ `.crosby` file's contents as a string.
76
+
77
+ ```ruby
78
+ exporter.to_s
79
+ ```
80
+
81
+ ### RSpec
82
+
83
+ `Crosby::RSpecHelper` works with RSpec 1, 2 & 3, and adds the `#crosby_email`
84
+ helper method. You can use this method to create `.crosby` files inside your
85
+ existing tests.
86
+
87
+ ```ruby
88
+ # spec_helper.rb
89
+
90
+ require "crosby/rspec_helper"
91
+
92
+ Crosby.config do |c|
93
+ # ...
94
+ end
95
+ ```
96
+
97
+ ```ruby
98
+ # spec/mailers/example_mailer_spec.rb
99
+ require "spec_helper"
100
+
101
+ describe ExampleMailer do
102
+ context "#notify" do
103
+ it "should send a notification email" do
104
+ mailer = ExampleMailer.notify(arg1, arg1)
105
+
106
+ # becomes
107
+ mailer = crosby_email(ExampleMailer, :notify, arg1, arg2)
108
+
109
+ # ...
110
+ end
111
+ end
112
+
113
+ # ...
114
+ end
115
+ ```
116
+
117
+ In the above example, Crosby will generate a uuid based on the mailer class,
118
+ method name and argument values. While this is fine, it may be helpful to
119
+ implicitly set the uuid. You can do this by setting the `@crosby_uuid` instance
120
+ variable in your test.
121
+
122
+ ```ruby
123
+ # spec/mailers/example_mailer_spec.rb
124
+ require "spec_helper"
125
+
126
+ describe ExampleMailer do
127
+ context "#notify" do
128
+ it "should send a notification email" do
129
+ @crosby_uuid = "example_mailer_notify"
130
+ mailer = crosby_email(ExampleMailer, :notify, arg1, arg2)
131
+
132
+ # ...
133
+ end
134
+ end
135
+
136
+ # ...
137
+ end
138
+ ```
139
+
140
+ ### Generating a diff
141
+
142
+ `Crosby::Diff` is responsible for comparing files of the same uuid to eachother.
143
+ There must be at least 2 files with the same uuid present in the configured
144
+ directory for a diff to be generated. If there are more than 2 files for a
145
+ given uuid, a diff will be generated for each unique pair of files.
146
+
147
+ ```ruby
148
+ Crosby::Diff.compare("example_mailer_notify")
149
+ # => [diff_str, ...]
150
+ ```
151
+
152
+ `Crosby::Diff.compare` returns an array of diff strings, one for each file pair.
153
+ When no pairs are present, `compare` returns an empty array.
154
+
155
+ ```ruby
156
+ Crosby::Diff.compare("not-an-existing-uuid")
157
+ # => []
158
+ ```
159
+
160
+ It also accepts an optional block, to be called once per diff string.
161
+
162
+ ```ruby
163
+ Crosby::Diff.compare("example_mailer_notify") { |diff| puts diff }
164
+ # diff output
165
+ # => [diff_str, ...]
166
+ ```
167
+
168
+ `Crosby::Diff.compare` and `Crosby::Diff.new` both accept an options hash to
169
+ override `Crosby.config` settings.
170
+
171
+ ```ruby
172
+ Crosby::Diff.compare("example_mailer_notify", :export_path => "../crosby_files")
173
+ Crosby::Diff.new("example_mailer_notify", :export_path => "../crosby_files")
174
+ ```
175
+
176
+ `Crosby::Diff` uses the excellent [Diffy gem](https://github.com/samg/diffy)
177
+ behind the scenes. If you would like access to the `Diffy::Diff` objects, you
178
+ can access them through the `Crosby::Diff#diffs` method.
179
+
180
+ ```ruby
181
+ cdiff = Crosby::Diff.new("example_mailer_notify")
182
+ cdiff.diffs
183
+ # => [ [#<Diffy::Diff:0x00000000>, #<Diffy::Diff:0x00000001], [..., ...], ... ]
184
+ ```
185
+
186
+ ### Rake
187
+
188
+ Crosby provides a simple `rake crosby:diff` command which outputs diffs for all
189
+ of the uuids represented by files in the directory specified at
190
+ `Crosby.config[:export_path]`.
191
+
192
+ ```ruby
193
+ # Rakefile
194
+ require "crosby/tasks"
195
+
196
+ Crosby.config do |c|
197
+ c.export_path = "../crosby_files"
198
+ end
199
+ ```
200
+
201
+ ```sh
202
+ bundle exec rake crosby:diff
203
+ ```
204
+
205
+ ## Contributing
206
+
207
+ 1. Fork it ( https://github.com/[my-github-username]/crosby/fork )
208
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
209
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
210
+ 4. Push to the branch (`git push origin my-new-feature`)
211
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :console do
4
+ require "crosby"
5
+ require "pry"
6
+ Pry.start
7
+ end
data/crosby.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "crosby/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "crosby"
8
+ spec.version = Crosby::VERSION
9
+ spec.authors = ["Dan Matthews"]
10
+ spec.email = ["dan.matthews@teamsnap.com"]
11
+ spec.summary = %q{Quality Assurance for ActionMailer}
12
+ spec.description = %q{Allows generation and comparison of email output}
13
+ spec.homepage = "https://github.com/teamsnap/crosby"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_dependency "diffy", "~> 3.0"
25
+ spec.add_dependency "nokogiri", "~> 1.6"
26
+ end
@@ -0,0 +1,25 @@
1
+ require "securerandom"
2
+
3
+ module Crosby
4
+ class Configuration
5
+ attr_accessor :app_name, :export_path
6
+
7
+ def initialize
8
+ self.app_name = SecureRandom.hex(4)
9
+ self.export_path = "tmp/crosby"
10
+ end
11
+
12
+ def config(&block)
13
+ block.call(self) if block_given?
14
+ to_hsh
15
+ end
16
+
17
+ def to_hsh
18
+ {
19
+ :app_name => app_name,
20
+ :export_path => export_path
21
+ }
22
+ end
23
+ alias :to_h :to_hsh
24
+ end
25
+ end
@@ -0,0 +1,81 @@
1
+ require "diffy"
2
+
3
+ module Crosby
4
+ class Diff
5
+ class << self
6
+ def compare(uuid, options = {}, &block)
7
+ new(uuid, options).compare(&block)
8
+ end
9
+ end
10
+
11
+ def initialize(uuid, options = {})
12
+ @uuid = uuid
13
+ @config = Crosby.config.merge(options)
14
+ end
15
+
16
+ # https://github.com/samg/diffy#supported-formats
17
+ def compare(format = :color, &block)
18
+ diffs.map { |diff|
19
+ out = diff.to_s(format)
20
+ block_given? ? block.call(out) : out
21
+ }
22
+ end
23
+
24
+ def diffs
25
+ @diffs ||= [].tap { |diffs|
26
+ pairs.each { |pair|
27
+ diffs << Diffy::Diff.new(
28
+ *pair,
29
+ :context => 0,
30
+ :include_diff_info => true,
31
+ :source => "files"
32
+ )
33
+ }
34
+ }
35
+ end
36
+
37
+ private
38
+
39
+ def build_file_paths(pairs)
40
+ pairs.map { |pair|
41
+ pair.map { |filename|
42
+ File.realpath(File.join(@config[:export_path], filename))
43
+ }
44
+ }
45
+ end
46
+
47
+ def files
48
+ matcher = Regexp.new("#{@uuid}\\.crosby\\z")
49
+
50
+ Dir.new(@config[:export_path]).entries.select { |entry|
51
+ entry =~ matcher ? true : false
52
+ }
53
+ end
54
+
55
+ def pairs
56
+ [
57
+ :unique_pairs,
58
+ :sort_pairs,
59
+ :build_file_paths
60
+ ].reduce([]) { |obj, meth|
61
+ send(meth, obj)
62
+ }
63
+ end
64
+
65
+ def sort_pairs(pairs)
66
+ pairs.map { |pair|
67
+ pair.first =~ Regexp.new(@config[:app_name]) ? pair.reverse : pair
68
+ }
69
+ end
70
+
71
+ def unique_pairs(arr)
72
+ arr.tap { |pairs|
73
+ files.repeated_permutation(2) { |permutation|
74
+ pairs << permutation.sort unless permutation.uniq.length == 1
75
+ }
76
+
77
+ pairs.uniq!
78
+ }
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,5 @@
1
+ module Crosby
2
+ MissingDependency = Class.new(StandardError)
3
+ MissingRSpec = Class.new(StandardError)
4
+ UnsupportedVersion = Class.new(StandardError)
5
+ end
@@ -0,0 +1,108 @@
1
+ require "fileutils"
2
+ require "securerandom"
3
+ require "nokogiri"
4
+
5
+ module Crosby
6
+ class Exporter
7
+ WRITE_MODE = "w"
8
+
9
+ attr_reader :mail
10
+
11
+ def initialize(mailer, method, uuid = SecureRandom.hex(8), *args)
12
+ @args = args
13
+ @mailer = mailer
14
+ @method = method
15
+ @uuid = uuid
16
+ @version = Crosby.action_mailer_version
17
+
18
+ config = Crosby.config
19
+ @path = config[:export_path]
20
+ @app_name = config[:app_name]
21
+ end
22
+
23
+ def export
24
+ ensure_path_exists
25
+ write
26
+ true
27
+ end
28
+
29
+ def to_s
30
+ create_mail unless mail
31
+
32
+ [
33
+ "TO: #{mail.to}",
34
+ "CC: #{mail.cc}",
35
+ "BCC: #{mail.bcc}",
36
+ "REPLY TO: #{mail.reply_to}",
37
+ "FROM: #{mail.from}",
38
+ "HTML:",
39
+ commonize_html(mail.html_part.body.raw_source),
40
+ "TEXT:",
41
+ commonize_text(mail.text_part.body.raw_source)
42
+ ].join("\n")
43
+ end
44
+
45
+ private
46
+
47
+ def commonize_html(str)
48
+ commonize_text(str)
49
+ compact(Nokogiri::HTML::Document.parse(commonize_text(str)).to_s)
50
+ end
51
+
52
+ def commonize_text(str)
53
+ str
54
+ .gsub(/([^=])=\n/, '\1') # single quotes required for encoding
55
+ .gsub(/=3D/, "=")
56
+ end
57
+
58
+ def compact(str)
59
+ str
60
+ .each_line
61
+ .reject(&:blank?)
62
+ .map{ |line|
63
+ line
64
+ .gsub(/\s+/, " ")
65
+ .gsub(/^ /, "")
66
+ .gsub(/ $/, "\n")
67
+ .gsub(/></, ">\n<")
68
+ }
69
+ .join
70
+ end
71
+
72
+ def create_mail
73
+ method = @method
74
+
75
+ case @version::MAJOR
76
+ when 2
77
+ method = "create_#{method}"
78
+ when 3
79
+ # supported, no additional action required
80
+ when 4
81
+ # supported, no additional action required
82
+ else
83
+ raise Crosby::UnsupportedVersion, "We do not yet support version " \
84
+ "#{@version::STRING} of ActionMailer"
85
+ end
86
+
87
+ @mail = @mailer.send(method, *@args)
88
+ end
89
+
90
+ def ensure_path_exists
91
+ @dir = Dir.new(FileUtils.mkdir_p(@path).first)
92
+ end
93
+
94
+ def file(&block)
95
+ File.open(filename, WRITE_MODE, &block)
96
+ end
97
+
98
+ def filename
99
+ File.join(@dir, "#{@mailer.name}.#{@method}.#{@app_name}.#{@uuid}.crosby")
100
+ end
101
+
102
+ def write
103
+ file do |f|
104
+ f.write(to_s)
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,31 @@
1
+ require "base64"
2
+ require "crosby"
3
+
4
+ module Crosby
5
+ module RSpecHelper
6
+ def crosby_email(mailer, method, *args)
7
+ @crosby_uuid ||= generate_crosby_digest(mailer, method, *args)
8
+ exporter = Crosby::Exporter.new(mailer, method, @crosby_uuid, *args)
9
+ return (exporter.export ? exporter.mail : false)
10
+ end
11
+
12
+ def generate_crosby_digest(*args)
13
+ Base64.encode64(args.map(&:to_s).join("|")).chomp
14
+ end
15
+ end
16
+ end
17
+
18
+ begin
19
+ if Kernel.const_defined?(:Spec)
20
+ class ActiveSupport::TestCase
21
+ include Crosby::RSpecHelper
22
+ end
23
+ else
24
+ RSpec.configure do |c|
25
+ c.include Crosby::RSpecHelper
26
+ end
27
+ end
28
+ rescue NameError
29
+ raise Crosby::MissingRSpec, "Crosby can't find RSpec at the Spec::Runner " \
30
+ "or RSpec namespace."
31
+ end
@@ -0,0 +1,44 @@
1
+ require "crosby"
2
+
3
+ module Crosby
4
+ class Tasks
5
+ include Rake::DSL if defined? Rake::DSL
6
+
7
+ def install_tasks
8
+ namespace :crosby do
9
+ desc "displays all diffs in the configured folder " +
10
+ "(#{Crosby.config[:export_path]})"
11
+ task :diff do
12
+ each_uuid do |uuid|
13
+ puts "============================================================"
14
+ puts "UUID: #{uuid}"
15
+ puts "============================================================"
16
+ Crosby::Diff.compare(uuid) { |diff| puts diff }
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def each_uuid(&block)
25
+ [].tap { |uuids|
26
+ Dir.new(Crosby.config[:export_path]).each { |filename|
27
+ uuids << extract_uuid(filename) if filename =~ /\.crosby$/
28
+ }
29
+
30
+ uuids.compact!
31
+ uuids.uniq!
32
+ uuids.sort!
33
+
34
+ uuids.each { |uuid| block.call(uuid) } if block_given?
35
+ }
36
+ end
37
+
38
+ def extract_uuid(filename)
39
+ filename.gsub(/^.+\..+\..+\.(\S+)\.crosby$/, '\1')
40
+ end
41
+ end
42
+ end
43
+
44
+ Crosby::Tasks.new.install_tasks
@@ -0,0 +1,3 @@
1
+ module Crosby
2
+ VERSION = "0.1.0"
3
+ end
data/lib/crosby.rb ADDED
@@ -0,0 +1,20 @@
1
+ require "crosby/version"
2
+
3
+ module Crosby
4
+ def self.config(&block)
5
+ @@configuration ||= Configuration.new
6
+ @@configuration.config(&block)
7
+ end
8
+
9
+ def self.action_mailer_version
10
+ require "action_mailer/version"
11
+ ActionMailer::VERSION
12
+ rescue
13
+ raise Crosby::MissingDependency, "Some version of ActionMailer is required"
14
+ end
15
+ end
16
+
17
+ require "crosby/configuration"
18
+ require "crosby/errors"
19
+ require "crosby/exporter"
20
+ require "crosby/diff"
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crosby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dan Matthews
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: diffy
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: nokogiri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ description: Allows generation and comparison of email output
70
+ email:
71
+ - dan.matthews@teamsnap.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - crosby.gemspec
82
+ - lib/crosby.rb
83
+ - lib/crosby/configuration.rb
84
+ - lib/crosby/diff.rb
85
+ - lib/crosby/errors.rb
86
+ - lib/crosby/exporter.rb
87
+ - lib/crosby/rspec_helper.rb
88
+ - lib/crosby/tasks.rb
89
+ - lib/crosby/version.rb
90
+ homepage: https://github.com/teamsnap/crosby
91
+ licenses:
92
+ - MIT
93
+ metadata: {}
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 2.2.2
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: Quality Assurance for ActionMailer
114
+ test_files: []