Current section
Files
Jump to
Current section
Files
lib/sentix.ex
defmodule Sentix do
# we need the `is_proc/1` macro
import Sentix.Macro
@moduledoc """
This module provides the Sentix interface to start a Sentix watcher and then
subscribe a process afterwards. This module is deliberately small as the aim
of Sentix is to provide as little behaviour on top of `fswatch` as possible.
"""
@doc """
Starts a Sentix watcher and links it to the current process.
This function requires the name of the watcher to start up, as well as a list
of paths. In addition you can provide a list of options which will be passed
through to `fswatch`. Please view the `fswatch` documentation for more information
as to the behaviour of these flags.
## Options
* `:access` - whether to receive notification of file access events.
* `:dir_only` - whether to only watch directories.
* `:excludes` - exclude patterns matching the provided (binary) Regex.
* `:filter` - only listen for events of this type (can be a list).
* `:includes` - include patterns matching the provided (binary) Regex.
* `:latency` - the latency of the monitor events.
* `:monitor` - specify a monitor to use, rather than the default.
* `:recursive` - whether or not to recurse subdirectories.
"""
@spec start_link(name :: atom, paths :: [ binary ], options :: Keyword.t) ::
{ :ok, pid } |
{ :error, reason :: atom | binary }
def start_link(name, paths, options \\ []) do
with { :ok, paths } <- enforce_paths(paths) do
__MODULE__.Watcher.start_link(name, paths, options)
end
end
@doc """
Shorthand around calling `start_link/3` and then simply removing the link.
Supports all the same options and works in an identical fashion to `start_link/3`.
"""
@spec start(name :: atom, paths :: [ binary ], options :: Keyword.t) ::
{ :ok, pid } |
{ :error, reason :: atom | binary }
def start(name, paths, options \\ []) do
with { :ok, pid } <- start_link(name, paths, options) do
:erlang.unlink(pid) && { :ok, pid }
end
end
@doc """
Subscribes a process to a Sentix watcher.
If no process name/pid is provided, this will subscribe the calling process. If
an invalid process identifier is provided, an error will be returned.
"""
@spec subscribe(name :: atom, sub :: atom | pid) ::
{ :ok, process :: number, subscribers :: [ pid ] } |
{ :error, :noproc }
def subscribe(name, sub \\ self()) when is_atom(name) and is_proc(sub) do
GenServer.call(name, { :subscribe, sub })
end
# Enforces that all provided paths are binaries. If any are not, then we just
# return an `:invalid_path` error to inform the user. If all paths are valid,
# then we expand all provided paths to make sure that everything is normalized
# further down the execution chain.
defp enforce_paths(paths) when is_list(paths) do
if Enum.all?(paths, &is_binary/1) do
{ :ok, Enum.map(paths, &Path.expand/1) }
else
{ :error, :invalid_path }
end
end
defp enforce_paths(path) when is_binary(path),
do: enforce_paths([path])
defp enforce_paths(_path),
do: { :error, :invalid_path }
end