Skip to content

Commit

Permalink
allows the emails to have before/after callbacks. Fixes #65
Browse files Browse the repository at this point in the history
  • Loading branch information
jwoertink committed Aug 13, 2022
1 parent 6cda3dd commit 9d6ea7b
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 1 deletion.
89 changes: 89 additions & 0 deletions spec/callbacks_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
require "./spec_helper"

abstract class BaseTestEmail < Carbon::Email
end

BaseTestEmail.configure do |setting|
setting.adapter = Carbon::DevAdapter.new
end

private class EmailWithBeforeCallbacks < BaseTestEmail
subject "My great subject"
from Carbon::Address.new("[email protected]")
to Carbon::Address.new("[email protected]")

property ran_before_callback : Bool = false

before_send do
self.ran_before_callback = true
end
end

private class EmailWithAfterCallbacks < BaseTestEmail
subject "My great subject"
from Carbon::Address.new("[email protected]")
to Carbon::Address.new("[email protected]")

property ran_after_callback : Bool = false

after_send do |_response|
self.ran_after_callback = true
end
end

private class EmailWithBothBeforeAndAfterCallbacks < BaseTestEmail
subject "My great subject"
from Carbon::Address.new("[email protected]")
to Carbon::Address.new("[email protected]")

property ran_before_callback : Bool = false
property ran_after_callback : Bool = false

before_send :mark_before_send
after_send :mark_after_send

private def mark_before_send
self.ran_before_callback = true
end

private def mark_after_send(_response)
self.ran_after_callback = true
end
end

describe "before/after callbacks" do
context "before an email is sent" do
it "runs the before_send callback" do
email = EmailWithBeforeCallbacks.new
email.ran_before_callback.should eq(false)
email.deliver
Carbon.should have_delivered_emails

email.ran_before_callback.should eq(true)
end
end

context "after an email is sent" do
it "runs the after_send callback" do
email = EmailWithAfterCallbacks.new
email.ran_after_callback.should eq(false)
email.deliver
Carbon.should have_delivered_emails

email.ran_after_callback.should eq(true)
end
end

context "running both callbacks" do
it "runs both callbacks" do
email = EmailWithBothBeforeAndAfterCallbacks.new
email.ran_before_callback.should eq(false)
email.ran_after_callback.should eq(false)
email.deliver
Carbon.should have_delivered_emails

email.ran_before_callback.should eq(true)
email.ran_after_callback.should eq(true)
end
end
end
81 changes: 81 additions & 0 deletions src/carbon/callbacks.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
module Carbon::Callbacks
# Runs the given method before the adapter calls `deliver_now`
#
# ```
# before_send :attach_metadata
#
# private def attach_metadata
# #...
# end
# ```
macro before_send(method_name)
before_send do
{{ method_name.id }}
end
end

# Runs the block before the adapter calls `deliver_now`
#
# ```
# before_send do
# #...
# end
# ```
macro before_send
def before_send
{% if @type.methods.map(&.name).includes?(:before_send.id) %}
previous_def
{% else %}
super
{% end %}

{{ yield }}
end
end

# Runs the given method after the adapter calls `deliver_now`.
# Passes in the return value of the adapter's `deliver_now` method.
#
# ```
# after_send :mark_email_as_sent
#
# private def mark_email_as_sent(response)
# # ...
# end
# ```
macro after_send(method_name)
after_send do |object|
{{ method_name.id }}(object)
end
end

# Runs the block after the adapter calls `deliver_now`, and passes the
# return value of the adapter's `deliver_now` method to the block.
#
# ```
# after_send do |response|
# # ...
# end
# ```
macro after_send(&block)
{%
if block.args.size != 1
raise <<-ERR
The 'after_send' callback requires exactly 1 block arg to be passed.
Example:
after_send { |value| some_method(value) }
ERR
end
%}
def after_send(%object)
{% if @type.methods.map(&.name).includes?(:after_send.id) %}
previous_def
{% else %}
super
{% end %}

{{ block.args.first }} = %object
{{ block.body }}
end
end
end
9 changes: 8 additions & 1 deletion src/carbon/email.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require "ecr"

abstract class Carbon::Email
include Carbon::Callbacks
alias Recipients = Carbon::Emailable | Array(Carbon::Emailable)

abstract def subject : String
Expand All @@ -25,6 +26,10 @@ abstract class Carbon::Email

def html_layout(content_io : IO); end

def before_send; end

def after_send(result); end

getter headers

macro inherited
Expand Down Expand Up @@ -122,7 +127,9 @@ abstract class Carbon::Email
end

def deliver
settings.adapter.deliver_now(self)
before_send
response = settings.adapter.deliver_now(self)
after_send(response)
end

def deliver_later
Expand Down

0 comments on commit 9d6ea7b

Please sign in to comment.