Shun.Builder (Shun v1.0.1) View Source

Provides a way to programmatically create modules that implement the Shun.Provider behaviour.

The Builder is supposed to be used in your own module, by calling use Shun.Builder. This in turn calls the __using__ macro and prepares the module for use with the DSL as defined by Shun.Rule.

The accept/1, reject/1 and handle/2 macros generate the relevant Shun.Rule structs, and enqueues them for compilation. On the other hand, Rules already defined in a Preset (any module which implements the Shun.Preset behaviour) can be incorporated with preset/1.

Rules are built and accumulated in the :rules module attribute.

Compilation

Based on the Rules given prior to compilation, the Builder emits implementations for handle_url/1, handle_ipv4/2 and handle_ipv6/2, the latter two called by an emitted implementation of handle_ip/1.

Functions are generated in the following order:

  • handle_ip/1 for IPv4, routing to handle_ipv4/2.
  • handle_ip/1 for IPv6, routing to handle_ipv6/2.
  • For each Rule, an implementation of handle_url/1, handle_ipv4/2, or handle_ipv6/2.
  • (Optional) Fallback implementation of handle_url/1.
  • (Optional) Fallback implementation of handle_ipv4/1.
  • (Optional) Fallback implementation of handle_ipv6/1.

The Builder also emits fallback clauses for all three types with the following defaults, in case you have not specified the corresponding patterns:

  • URIs are resolved, and their IP addresses are verified (via :resolve).
  • IP addresses that are not IPv4 or IPv6 are rejected (via :reject).
  • IPv4 addresses are rejected (via :reject).
  • IPv6 addresses are rejected (via :reject).

You can override this behavior by ensuring that the patterns completely cover each Target type. For example, to implement a Provider that rejects all unknown URIs instead of resolving them (and rejecting their IP addresses by default), implement a fallback clause for URIs:

defmodule MyApp.Shun do
  use Shun.Builder
  accept %URI{host: host} when host == "example.com"
  reject %URI{}
end

You can also use the fallback clause with a function reference (see handle/2) to implement custom fallback logic:

defmodule MyApp.Shun do
  use Shun.Builder
  accept %URI{host: host} when host == "example.com"
  handle %URI{}, &handle_uri/1

  def handle_uri(uri) do
    cond do
      uri.host == "test.example.com" -> :accept
      true -> :reject
    end
  end
end

For example, to implement a Provider that accepts all unknown IP addresses, implement fallback clauses for both IPv4 and IPv6 addresses:

defmodule MyApp.Shun do
  use Shun.Builder
  
  accept {_, _, _, _}
  accept {_, _, _, _, _, _, _, _}
end

Link to this section Summary

Functions

Adds an Accept rule generated with Shun.Rule.accept/1, or Accept rules generated by the preset module provided.

Adds Dynamic rules generated by the preset module provided, with its default handler function used to handle the matched entries.

Adds a Dynamic rule generated with Shun.Rule.handle/2, or Dynamic rules generated by the preset module provided.

Adds an Reject rule generated with Shun.Rule.accept/1, or Reject rules generated by the preset module provided.

Link to this section Functions

Link to this macro

accept(target)

View Source (macro)

Specs

accept(module() | Shun.Rule.Target.t()) :: Macro.t()

Adds an Accept rule generated with Shun.Rule.accept/1, or Accept rules generated by the preset module provided.

Link to this macro

handle(target)

View Source (macro)

Specs

handle(module()) :: Macro.t()

Adds Dynamic rules generated by the preset module provided, with its default handler function used to handle the matched entries.

Link to this macro

handle(target, handler)

View Source (macro)

Specs

Adds a Dynamic rule generated with Shun.Rule.handle/2, or Dynamic rules generated by the preset module provided.

Link to this macro

reject(target)

View Source (macro)

Specs

reject(module() | Shun.Rule.Target.t()) :: Macro.t()

Adds an Reject rule generated with Shun.Rule.accept/1, or Reject rules generated by the preset module provided.