Packages

An iterative directory listing for Elixir.

Current section

Files

Jump to
exdir lib ex_dir stream.ex
Raw

lib/ex_dir/stream.ex

defmodule ExDir.Stream do
@moduledoc """
Defines a `ExDir.Stream` struct returned by `ExDir.stream!/2`.
The following fields are public:
* `path` - the directory path
* `recursive` - if file listing is recursive
* `raw` - if any filename should be returned, even invalid Unicode names
* `type` - if file types should be also returned
"""
defstruct path: nil, recursive: false, options: []
@type t :: %__MODULE__{}
@doc false
def __build__(path, recursive, options \\ []),
do: %ExDir.Stream{path: path, recursive: recursive, options: options}
defimpl Enumerable do
def reduce(%{path: path, recursive: recursive, options: options}, acc, fun) do
Stream.resource(
fn -> opendir!(path) end,
&readdir!(&1, recursive, options),
& &1
).(acc, fun)
end
defp opendir!(path) do
case :dirent.opendir(path) do
{:ok, dir} ->
[{dir, path}]
{:error, reason} ->
raise ExDir.Error,
reason: reason,
action: "read directory",
path: path
end
end
defp readdir!([{dir, path} | rest] = stack, recursive, options) do
mode = Keyword.get(options, :read, :type)
case ExDir.read(dir, read: mode) do
nil ->
case rest do
[] -> {:halt, dir}
_other -> readdir!(rest, recursive, options)
end
{:error, reason} ->
raise ExDir.Error,
reason: reason,
action: "read directory",
path: path
{file_type, file_path} ->
inspect_type(file_path, file_type, stack, recursive, options)
end
end
defp inspect_type(file_path, :directory, stack, true, options),
do: readdir!(opendir!(file_path) ++ stack, true, options)
defp inspect_type(file_path, file_type, stack, _recursive, options)
when file_type != :unknown do
case Keyword.get(options, :read) do
nil ->
{[file_path], stack}
_ ->
{[{file_type, file_path}], stack}
end
end
defp inspect_type(file_path, :unknown, stack, recursive, options) do
%{type: file_type} = File.lstat!(file_path)
inspect_type(file_path, file_type, stack, recursive, options)
end
def count(_stream) do
{:error, __MODULE__}
end
def member?(_stream, _term) do
{:error, __MODULE__}
end
def slice(_stream) do
{:error, __MODULE__}
end
end
end