Merge branch 'develop' into unstable

This commit is contained in:
Luca Guidi 2020-10-19 09:40:38 +02:00
commit 3a14b64015
No known key found for this signature in database
GPG Key ID: 4F9DE2097876665B
19 changed files with 214 additions and 128 deletions

View File

@ -4,10 +4,10 @@
# #
version: 2 version: 2
jobs: jobs:
"ruby-2.5": "ruby-2.6":
docker: docker:
- image: hanami/ruby-2.5 - image: hanami/ruby-2.6
working_directory: ~/hanami-utils working_directory: ~/hanami-mailer
steps: steps:
- checkout - checkout
# Download and cache dependencies # Download and cache dependencies
@ -29,10 +29,10 @@ jobs:
name: run tests name: run tests
command: | command: |
./script/ci ./script/ci
"ruby-2.6": "ruby-2.7":
docker: docker:
- image: hanami/ruby-2.6 - image: hanami/ruby-2.7
working_directory: ~/hanami-utils working_directory: ~/hanami-mailer
steps: steps:
- checkout - checkout
# Download and cache dependencies # Download and cache dependencies
@ -59,5 +59,5 @@ workflows:
version: 2 version: 2
build: build:
jobs: jobs:
- "ruby-2.5"
- "ruby-2.6" - "ruby-2.6"
- "ruby-2.7"

View File

@ -1,22 +0,0 @@
language: ruby
sudo: false
cache: bundler
before_script:
- gem update --system
script: ./script/ci
rvm:
- 2.5
- 2.6
- ruby-head
matrix:
allow_failures:
- rvm: ruby-head
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/fde2367248d53de4fe70
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: never # options: [always|never|change] default: always

View File

@ -1,9 +1,16 @@
# Hanami::Mailer # Hanami::Mailer
Mail for Ruby applications Mail for Ruby applications
<<<<<<< HEAD
## v2.0.0.alpha1 (unreleased) ## v2.0.0.alpha1 (unreleased)
### Changed ### Changed
- [Luca Guidi] Drop support for Ruby: MRI 2.3, and 2.4. - [Luca Guidi] Drop support for Ruby: MRI 2.3, and 2.4.
=======
## v1.3.2 - 2020-02-03
### Added
- [Luca Guidi] Official support for Ruby: MRI 2.7
- [glaszig] Added `Hanami::Mailer.return_path` and `#return_path` to specify `MAIL FROM` address
>>>>>>> develop
## v1.3.1 - 2019-01-18 ## v1.3.1 - 2019-01-18
### Added ### Added

View File

@ -4,9 +4,8 @@ source "https://rubygems.org"
gemspec gemspec
unless ENV["CI"] unless ENV["CI"]
gem "byebug", require: false, platforms: :mri gem "byebug", require: false, platforms: :mri
gem "allocation_stats", require: false gem "yard", require: false
gem "benchmark-ips", require: false
end end
gem "hanami-utils", "~> 2.0.alpha", require: false, git: "https://github.com/hanami/utils.git", branch: "unstable" gem "hanami-utils", "~> 2.0.alpha", require: false, git: "https://github.com/hanami/utils.git", branch: "unstable"

View File

@ -5,9 +5,8 @@ Mail for Ruby applications.
## Status ## Status
[![Gem Version](https://badge.fury.io/rb/hanami-mailer.svg)](https://badge.fury.io/rb/hanami-mailer) [![Gem Version](https://badge.fury.io/rb/hanami-mailer.svg)](https://badge.fury.io/rb/hanami-mailer)
[![TravisCI](https://travis-ci.org/hanami/mailer.svg?branch=master)](https://travis-ci.org/hanami/mailer) [![CircleCI](https://circleci.com/gh/hanami/mailer/tree/unstable.svg?style=svg)](https://circleci.com/gh/hanami/mailer/tree/unstable)
[![CircleCI](https://circleci.com/gh/hanami/mailer/tree/master.svg?style=svg)](https://circleci.com/gh/hanami/mailer/tree/master) [![Test Coverage](https://codecov.io/gh/hanami/mailer/branch/unstable/graph/badge.svg)](https://codecov.io/gh/hanami/mailer)
[![Test Coverage](https://codecov.io/gh/hanami/mailer/branch/master/graph/badge.svg)](https://codecov.io/gh/hanami/mailer)
[![Depfu](https://badges.depfu.com/badges/739c6e10eaf20d3ba4240d00828284db/overview.svg)](https://depfu.com/github/hanami/mailer?project=Bundler) [![Depfu](https://badges.depfu.com/badges/739c6e10eaf20d3ba4240d00828284db/overview.svg)](https://depfu.com/github/hanami/mailer?project=Bundler)
[![Inline Docs](http://inch-ci.org/github/hanami/mailer.svg)](http://inch-ci.org/github/hanami/mailer) [![Inline Docs](http://inch-ci.org/github/hanami/mailer.svg)](http://inch-ci.org/github/hanami/mailer)
@ -22,7 +21,7 @@ Mail for Ruby applications.
## Rubies ## Rubies
__Hanami::Mailer__ supports Ruby (MRI) 2.5+ __Hanami::Mailer__ supports Ruby (MRI) 2.6+
## Installation ## Installation
@ -128,6 +127,7 @@ configuration = Hanami::Mailer::Configuration.new do |config|
end end
class WelcomeMailer < Hanami::Mailer class WelcomeMailer < Hanami::Mailer
return_path 'bounce@sender.com'
from 'noreply@sender.com' from 'noreply@sender.com'
to 'noreply@recipient.com' to 'noreply@recipient.com'
cc 'cc@sender.com' cc 'cc@sender.com'
@ -447,6 +447,6 @@ __Hanami::Mailer__ uses [Semantic Versioning 2.0.0](http://semver.org)
## Copyright ## Copyright
Copyright © 2015-2019 Luca Guidi Released under MIT License Copyright © 2015-2020 Luca Guidi Released under MIT License
This project was formerly known as Lotus (`lotus-mailer`). This project was formerly known as Lotus (`lotus-mailer`).

View File

@ -40,9 +40,9 @@ total_memsize = stats.allocations.bytes.to_a.inject(&:+)
puts "total memsize: #{total_memsize}" puts "total memsize: #{total_memsize}"
detailed_allocations = stats.allocations(alias_paths: true) detailed_allocations = stats.allocations(alias_paths: true)
.group_by(:sourcefile, :class_plus) .group_by(:sourcefile, :class_plus)
.sort_by_count .sort_by_count
.to_text .to_text
puts "allocations by source file and class:" puts "allocations by source file and class:"
puts detailed_allocations puts detailed_allocations

View File

@ -15,17 +15,18 @@ Gem::Specification.new do |spec|
spec.homepage = "http://hanamirb.org" spec.homepage = "http://hanamirb.org"
spec.license = "MIT" spec.license = "MIT"
spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-mailer.gemspec`.split($/) # rubocop:disable Style/SpecialGlobalVars spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-mailer.gemspec`.split($/)
spec.bindir = "exe" spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"] spec.require_paths = ["lib"]
spec.required_ruby_version = ">= 2.5.0" spec.required_ruby_version = ">= 2.6.0"
spec.add_dependency "hanami-utils", "~> 2.0.alpha" spec.add_dependency "hanami-utils", "~> 2.0.alpha"
spec.add_dependency "tilt", "~> 2.0", ">= 2.0.1" spec.add_dependency "tilt", "~> 2.0", ">= 2.0.1"
spec.add_dependency "mail", "~> 2.6" spec.add_dependency "mail", "~> 2.6"
spec.add_development_dependency "bundler", ">= 1.6", "< 3" spec.add_development_dependency "bundler", ">= 1.6", "< 3"
spec.add_development_dependency "rake", "~> 12" spec.add_development_dependency "rake", "~> 13"
spec.add_development_dependency "rspec", "~> 3.7" spec.add_development_dependency "rspec", "~> 3.7"
spec.add_development_dependency "rubocop", "0.91"
end end

View File

@ -77,6 +77,7 @@ module Hanami
# @since next # @since next
# @api unstable # @api unstable
def self.inherited(base) def self.inherited(base)
super
@_subclasses.push(base) @_subclasses.push(base)
base.extend Dsl base.extend Dsl
end end
@ -168,15 +169,15 @@ module Hanami
# mailer.deliver(invoice: invoice, user: user, charset: 'iso-8859') # mailer.deliver(invoice: invoice, user: user, charset: 'iso-8859')
def deliver(locals) def deliver(locals)
mail(locals).deliver mail(locals).deliver
rescue ArgumentError => e rescue ArgumentError => exception
raise MissingDeliveryDataError if e.message =~ /SMTP (From|To) address/ raise MissingDeliveryDataError if exception.message =~ /SMTP (From|To) address/
raise raise
end end
# @since next # @since next
# @api unstable # @api unstable
alias call deliver alias_method :call, :deliver
# Render a single template with the specified format. # Render a single template with the specified format.
# #
@ -208,17 +209,16 @@ module Hanami
# @api unstable # @api unstable
# @since next # @since next
# #
# rubocop:disable Metrics/AbcSize def bind(mail, locals) # rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def bind(mail, locals)
charset = locals.fetch(:charset, configuration.default_charset) charset = locals.fetch(:charset, configuration.default_charset)
mail.from = __dsl(:from, locals) mail.return_path = __dsl(:return_path, locals)
mail.to = __dsl(:to, locals) mail.from = __dsl(:from, locals)
mail.cc = __dsl(:cc, locals) mail.to = __dsl(:to, locals)
mail.bcc = __dsl(:bcc, locals) mail.cc = __dsl(:cc, locals)
mail.reply_to = __dsl(:reply_to, locals) mail.bcc = __dsl(:bcc, locals)
mail.subject = __dsl(:subject, locals) mail.reply_to = __dsl(:reply_to, locals)
mail.subject = __dsl(:subject, locals)
mail.html_part = __part(:html, charset, locals) mail.html_part = __part(:html, charset, locals)
mail.text_part = __part(:txt, charset, locals) mail.text_part = __part(:txt, charset, locals)
@ -226,8 +226,6 @@ module Hanami
mail.charset = charset mail.charset = charset
mail.delivery_method(*configuration.delivery_method) mail.delivery_method(*configuration.delivery_method)
end end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/AbcSize
# @since next # @since next
# @api unstable # @api unstable

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "set"
require "hanami/utils/kernel" require "hanami/utils/kernel"
require "hanami/mailer/template_name" require "hanami/mailer/template_name"
require "hanami/mailer/templates_finder" require "hanami/mailer/templates_finder"
@ -154,7 +155,7 @@ module Hanami
@modules = [] @modules = []
end end
alias unload! reset! alias_method :unload!, :reset!
# Copy the configuration for the given mailer # Copy the configuration for the given mailer
# #

View File

@ -15,14 +15,15 @@ module Hanami
# @api unstable # @api unstable
def self.extended(base) def self.extended(base)
base.class_eval do base.class_eval do
@from = nil @from = nil
@to = nil @to = nil
@cc = nil @cc = nil
@bcc = nil @bcc = nil
@reply_to = nil @reply_to = nil
@subject = nil @return_path = nil
@template = nil @subject = nil
@before = ->(*) {} @template = nil
@before = ->(*) {}
end end
end end
@ -210,6 +211,73 @@ module Hanami
end end
end end
# Sets the bcc (blind carbon copy) for mail messages
#
# It accepts a hardcoded value as a string or array of strings.
# For dynamic values, you can specify a symbol that represents an instance
# method.
#
# This value is optional.
#
# When a value is given, it specifies the bcc for the email.
# When a value is not given, it returns the bcc of the email.
#
# This is part of a DSL, for this reason when this method is called with
# an argument, it will set the corresponding class variable. When
# called without, it will return the already set value, or the default.
#
# @overload bcc(value)
# Sets the bcc
# @param value [String, Array, Symbol] the hardcoded value or method name
# @return [NilClass]
#
# @overload bcc
# Returns the bcc
# @return [String, Array, Symbol] the recipient
#
# @since 0.3.0
#
# @example Hardcoded value (String)
# require 'hanami/mailer'
#
# class WelcomeMailer < Hanami::Mailer
# bcc "other.user@example.com"
# end
#
# @example Hardcoded value (Array)
# require 'hanami/mailer'
#
# class WelcomeMailer < Hanami::Mailer
# bcc ["other.user-1@example.com", "other.user-2@example.com"]
# end
#
# @example Lazy value (Proc)
# require 'hanami/mailer'
#
# class WelcomeMailer < Hanami::Mailer
# bcc ->(locals) { locals.fetch(:user).email }
# end
#
# user = User.new(name: 'L')
# WelcomeMailer.new(configuration: configuration).deliver(user: user)
#
# @example Lazy values (Proc)
# require 'hanami/mailer'
#
# class WelcomeMailer < Hanami::Mailer
# bcc ->(locals) { locals.fetch(:users).map(&:email) }
# end
#
# users = [User.new(name: 'L'), User.new(name: 'MG')]
# WelcomeMailer.new(configuration: configuration).deliver(users: users)
def bcc(value = nil)
if value.nil?
@bcc
else
@bcc = value
end
end
# Sets the reply_to for mail messages # Sets the reply_to for mail messages
# #
# It accepts a hardcoded value as a string or array of strings. # It accepts a hardcoded value as a string or array of strings.
@ -299,70 +367,60 @@ module Hanami
end end
end end
# Sets the bcc (blind carbon copy) for mail messages # Sets the MAIL FROM address for mail messages.
# This lets you specify a "bounce address" different from the sender
# address specified with `from`.
# #
# It accepts a hardcoded value as a string or array of strings. # It accepts a hardcoded value as a string, or a symbol that represents
# For dynamic values, you can specify a symbol that represents an instance # an instance method for more complex logic.
# method.
# #
# This value is optional. # This value is optional.
# #
# When a value is given, it specifies the bcc for the email. # When a value is given, specify the MAIL FROM address of the email
# When a value is not given, it returns the bcc of the email. # Otherwise, it returns the MAIL FROM address of the email
# #
# This is part of a DSL, for this reason when this method is called with # This is part of a DSL, for this reason when this method is called with
# an argument, it will set the corresponding class variable. When # an argument, it will set the corresponding class variable. When
# called without, it will return the already set value, or the default. # called without, it will return the already set value, or the default.
# #
# @overload bcc(value) # @overload return_path(value)
# Sets the bcc # Sets the MAIL FROM address
# @param value [String, Array, Symbol] the hardcoded value or method name # @param value [String, Symbol] the hardcoded value or method name
# @return [NilClass] # @return [NilClass]
# #
# @overload bcc # @overload return_path
# Returns the bcc # Returns the MAIL FROM address
# @return [String, Array, Symbol] the recipient # @return [String, Symbol] the MAIL FROM address
# #
# @since 0.3.0 # @since 1.3.2
# #
# @example Hardcoded value (String) # @example Hardcoded value (String)
# require 'hanami/mailer' # require 'hanami/mailer'
# #
# class WelcomeMailer < Hanami::Mailer # class WelcomeMailer
# bcc "other.user@example.com" # include Hanami::Mailer
#
# return_path "bounce@example.com"
# end # end
# #
# @example Hardcoded value (Array) # @example Method (Symbol)
# require 'hanami/mailer' # require 'hanami/mailer'
# #
# class WelcomeMailer < Hanami::Mailer # class WelcomeMailer
# bcc ["other.user-1@example.com", "other.user-2@example.com"] # include Hanami::Mailer
# return_path :bounce_address
#
# private
#
# def bounce_address
# "bounce@example.com"
# end
# end # end
# def return_path(value = nil)
# @example Lazy value (Proc)
# require 'hanami/mailer'
#
# class WelcomeMailer < Hanami::Mailer
# bcc ->(locals) { locals.fetch(:user).email }
# end
#
# user = User.new(name: 'L')
# WelcomeMailer.new(configuration: configuration).deliver(user: user)
#
# @example Lazy values (Proc)
# require 'hanami/mailer'
#
# class WelcomeMailer < Hanami::Mailer
# bcc ->(locals) { locals.fetch(:users).map(&:email) }
# end
#
# users = [User.new(name: 'L'), User.new(name: 'MG')]
# WelcomeMailer.new(configuration: configuration).deliver(users: users)
def bcc(value = nil)
if value.nil? if value.nil?
@bcc @return_path
else else
@bcc = value @return_path = value
end end
end end

View File

@ -11,8 +11,8 @@ module Hanami
# #
# TODO this is identical to Hanami::View, consider to move into Hanami::Utils # TODO this is identical to Hanami::View, consider to move into Hanami::Utils
class Template class Template
def initialize(template) def initialize(template, encoding = Encoding::UTF_8)
@_template = Tilt.new(template) @_template = Tilt.new(template, default_encoding: encoding)
freeze freeze
end end

View File

@ -18,7 +18,7 @@ module Hanami
class << self class << self
# @since next # @since next
# @api unstable # @api unstable
alias [] call alias_method :[], :call
end end
end end
end end

View File

@ -98,7 +98,10 @@ module Hanami
# @api unstable # @api unstable
# @since 0.1.0 # @since 0.1.0
def templates(template_name, lookup = search_path) def templates(template_name, lookup = search_path)
Utils::FileList["#{[root, lookup, template_name].join(separator)}#{format_separator}#{format}#{format_separator}#{engines}"] root_path = [root, lookup, template_name].join(separator)
search_path = "#{format_separator}#{format}#{format_separator}#{engines}"
Utils::FileList["#{root_path}#{search_path}"]
end end
# @api unstable # @api unstable

View File

@ -26,11 +26,11 @@ upload_code_coverage() {
} }
main() { main() {
prepare_build && prepare_build
print_ruby_version && print_ruby_version
run_code_quality_checks && run_code_quality_checks
run_unit_tests && run_unit_tests
upload_code_coverage upload_code_coverage
} }
main main

View File

@ -120,7 +120,7 @@ RSpec.describe Hanami::Mailer do
subject { options.fetch(:deliveries).first } subject { options.fetch(:deliveries).first }
let(:mailer) { WelcomeMailer.new(configuration: configuration) } let(:mailer) { WelcomeMailer.new(configuration: configuration) }
let(:options) { { deliveries: [] } } let(:options) { {deliveries: []} }
let(:configuration) do let(:configuration) do
configuration = Hanami::Mailer::Configuration.new do |config| configuration = Hanami::Mailer::Configuration.new do |config|

View File

@ -62,11 +62,12 @@ class ProcMailer < Hanami::Mailer
end end
class WelcomeMailer < Hanami::Mailer class WelcomeMailer < Hanami::Mailer
from "noreply@sender.com" from "noreply@sender.com"
to ["noreply@recipient.com", "owner@recipient.com"] to ["noreply@recipient.com", "owner@recipient.com"]
cc "cc@recipient.com" cc "cc@recipient.com"
bcc "bcc@recipient.com" bcc "bcc@recipient.com"
reply_to "reply_to@recipient.com" reply_to "reply_to@recipient.com"
return_path "bounce@sender.com"
subject "Welcome" subject "Welcome"

View File

@ -63,22 +63,22 @@ RSpec.describe Hanami::Mailer::Configuration do
describe "set with a symbol" do describe "set with a symbol" do
before do before do
subject.delivery_method = :exim, { location: "/path/to/exim" } subject.delivery_method = :exim, {location: "/path/to/exim"}
end end
it "saves the delivery method in the configuration" do it "saves the delivery method in the configuration" do
expect(subject.delivery_method).to eq([:exim, { location: "/path/to/exim" }]) expect(subject.delivery_method).to eq([:exim, {location: "/path/to/exim"}])
end end
end end
describe "set with a class" do describe "set with a class" do
before do before do
subject.delivery_method = MandrillDeliveryMethod, subject.delivery_method = MandrillDeliveryMethod,
{ username: "mandrill-username", password: "mandrill-api-key" } {username: "mandrill-username", password: "mandrill-api-key"}
end end
it "saves the delivery method in the configuration" do it "saves the delivery method in the configuration" do
expect(subject.delivery_method).to eq([MandrillDeliveryMethod, username: "mandrill-username", password: "mandrill-api-key"]) expect(subject.delivery_method).to eq([MandrillDeliveryMethod, {username: "mandrill-username", password: "mandrill-api-key"}])
end end
end end
end end

View File

@ -76,6 +76,46 @@ RSpec.describe Hanami::Mailer::Dsl do
end end
end end
describe ".reply_to" do
it "returns the default value" do
expect(mailer.reply_to).to be(nil)
end
it "sets a single value" do
email_address = "reply@hanami.test"
mailer.reply_to email_address
expect(mailer.reply_to).to eq(email_address)
end
it "sets an array of values" do
email_addresses = ["bcc@hanami.test"]
mailer.reply_to email_addresses
expect(mailer.reply_to).to eq(email_addresses)
end
end
describe ".return_path" do
it "returns the default value" do
expect(mailer.return_path).to be(nil)
end
it "sets a single value" do
email_address = "return@hanami.test"
mailer.return_path email_address
expect(mailer.return_path).to eq(email_address)
end
it "sets an array of values" do
email_addresses = ["return@hanami.test"]
mailer.return_path email_addresses
expect(mailer.return_path).to eq(email_addresses)
end
end
describe ".subject" do describe ".subject" do
it "returns the default value" do it "returns the default value" do
expect(mailer.subject).to be(nil) expect(mailer.subject).to be(nil)

View File

@ -151,7 +151,7 @@ RSpec.describe Hanami::Mailer do
describe "when locals are parsed in" do describe "when locals are parsed in" do
let(:mailer) { RenderMailer.new(configuration: configuration) } let(:mailer) { RenderMailer.new(configuration: configuration) }
let(:locals) { { user: User.new("Luca") } } let(:locals) { {user: User.new("Luca")} }
it "renders template with parsed locals" do it "renders template with parsed locals" do
expect(mailer.render(:html, locals)).to include(locals.fetch(:user).name) expect(mailer.render(:html, locals)).to include(locals.fetch(:user).name)
@ -160,7 +160,7 @@ RSpec.describe Hanami::Mailer do
describe "with HAML template engine" do describe "with HAML template engine" do
let(:mailer) { TemplateEngineMailer.new(configuration: configuration) } let(:mailer) { TemplateEngineMailer.new(configuration: configuration) }
let(:locals) { { user: User.new("MG") } } let(:locals) { {user: User.new("MG")} }
it "renders template with parsed locals" do it "renders template with parsed locals" do
expect(mailer.render(:html, locals)).to include(%(<h1>\n#{locals.fetch(:user).name}\n</h1>\n)) expect(mailer.render(:html, locals)).to include(%(<h1>\n#{locals.fetch(:user).name}\n</h1>\n))