Consider following plug conventions and implementing pipeline/pipe macros
Consider following plug conventions:init/1 and call/2. Also would be more natural to have pipeline/pipe macros. I.e.:
defmodule MyApp.MyEvent do
use Ravenx.Pipeline
use MyApp.PhoenixSlackPipe, view: MyApp.SlackView, template: "new_slack_event.text"
use MyApp.PhoenixEmailPipe, view: MyApp.EmailView, template: "new_email_event.text"
pipe :slack, channel: "events", async: true
pipe :email, contact: & &1.assigns.user.email, subject: &"Welcome #{&1.assigns.user.name}"
def call(pipeline, _opts, payload) do
user = MyApp.Repo.preload(payload, :friends)
pipeline.assign(:user, user)
end
end
and for a pipe:
defmodule MyApp.PhoenixSlackPipe do
use Ravenx.Pipe
use MyApp.PhoenixSlack # `channel/2`, `render_title/2`, `render_body/3`, `send/1`
def init(_pipeline, options) do
options
end
def call(pipeline, options) do
pipeline
|> channel(options[:channel])
|> render_title(options[:title])
|> render_body(options[:view], options[:template]) # renders with `pipeline.assigns`
|> send
end
end
This type of design would make it so you don't have to load strategies in your config (which doesn't seem necessary), instead you just use them in your Pipe files.
Hi @Sitch !
First of all, thanks a lot for sharing the idea. We think it's amazing and it's definitively the way we should focus the next major release of Ravenx.
This change alongside with #28 to reduce unnecessary dependencies are two improvements that can make this library a better one.
If you feel comfortable to participate in the development, you are more than welcome. Otherwise don't worry, the fact of giving us the idea is more than enough.
Thanks! ❤️
Thanks :) Take a look at https://github.com/appunite/piper
Thinking about the approach we can take on this, these are the ideas that came up to my mind (are a version of what was firstly exposed by @Sitch)
defmodule MyApp.Notifications.NewEvent do
use Ravenx.Pipeline
@slack_config [
view: MyApp.NotificationsView,
template: "slack_event.text",
channel: "events",
async: true
]
@email_config [
view: MyApp.NotificationsView,
template: "email_event.text",
subject: &("Welcome #{&1.assigns.user.name}")
]
pipe MyApp.SlackStrategy, @slack_config
pipe MyApp.EmailStrategy, @email_config
def init do
[]
end
def call(instance, _opts, payload) do
user = MyApp.Repo.preload(payload, :friends)
instance.assign(:user, user)
end
end
defmodule MyApp.SlackStrategy do
use Ravenx.Pipe
use Ravenx.Strategies.Slack # `channel/2`, `render_title/2`, `render_body/3`, `send/1`
def init(opts) do
options
end
def call(instance, opts) do
instance
|> channel(opts[:channel])
|> render_title(opts[:title])
|> render_body(opts[:view], opts[:template])
|> deliver
end
end
The app's strategies are intended to be a custom configuration (and use) of the integration itself, specifying how a (for example, Slack) integration is built in the app itself.
And the Ravenx.Strategies.Slack should integrate the helper functions used to fill the instance data and the deliver function.
The Ravenx.Pipeline macro will inject the deliver and deliver_async methods in the notification modules.
Also, the init methods will be evaluated on compile time, so they can be used, like in Plug library, to pre-calculate configurations.