ravenx
                                
                                 ravenx copied to clipboard
                                
                                    ravenx copied to clipboard
                            
                            
                            
                        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.