View Source Rewrite (rewrite v1.0.1)
Rewrite
is a tool for modifying, adding and removing files in a Mix
project.
The package is intended for use in Mix
tasks. Rewrite
itself uses functions
provided by Mix
.
With Rewrite.read!/2
you can load the whole project. Then you can modify the
project with a number of functions provided by Rewrite
and Rewrite.Source
without writing any changes back to the file system. All changes are stored in
the source structs. Any version of a source is available in the project. To
write the whole project back to the file system, the Rewrite.write_all/2
can
be used.
Elixir source files can be modified by modifying the AST. For this Rewrite
uses the Sourceror
package to create the AST and to convert it back. The
Sourceror
package also provides all the utilities needed to manipulate the
AST.
Sources can also receive a Rewrite.Issue
to document problems or information
with the source.
Rewrite
respects the .formatter.exs
in the project when rewriting sources.
To do this, the formatter can be read by Rewrite.DotFormatter
and the
resulting DotFormatter struct can be used in the function to update the
sources.
Summary
Functions
Counts the sources with the given extname
in the rewrite
project.
Creates a new %Source{}
without putting it to the %Rewrite{}
project.
Deletes the source for the given path
from the rewrite
.
Returns the DotFormatter
for the given rewrite
project.
Sets a dot_formatter
for the given rewrite
project.
Drops the sources with the given paths
from the rewrite
project.
Returns the extension of the given file
.
Formats the given rewrite
project with the given dot_formatter
.
The same as format/2
but raises an exception in case of an error.
Formats a source in a rewrite
project.
The same as format_source/3
but raises an exception in case of an error.
Creates a %Rewrite{}
from the given sources.
Same as from_sources/2
, but raises a Rewrite.Error
exception in case of
failure.
Returns true
when the %Rewrite{}
contains a %Source{}
with the given
path
.
Returns true
if any source has one or more issues.
Invokes fun
for each source
in the rewrite
project and updates the
rewirte
project with the result of fun
.
Return a rewrite
project where each source
is the result of invoking
fun
on each source
of the given rewrite
project.
Moves a source from one path to another.
Same as move/4
, but raises an exception in case of failure.
Creates an empty project.
Creates a %Rewrite{}
from the given inputs
.
Creates a new %Source{}
and puts the source to the %Rewrite{}
project.
Same as new_source/4
, but raises a Rewrite.Error
exception in case of failure.
Returns a sorted list of all paths in the rewrite
project.
Puts the given source
to the given rewrite
project.
Same as put/2
, but raises a Rewrite.Error
exception in case of failure.
Reads the given input
/inputs
and adds the source/sources to the project
when not already readed.
Tries to delete the source
file in the file system and removes the source
from the rewrite
project.
Same as source/2
, but raises a Rewrite.Error
exception in case of failure.
Returns the %Rewrite.Source{}
for the given path
.
Same as source/2
, but raises a Rewrite.Error
exception in case of
failure.
Returns all sources sorted by path.
Updates the given source
in the rewrite
project.
Updates a source for the given path
in the rewrite
project.
The same as update/2
but raises a Rewrite.Error
exception in case
of an error.
The same as update/3
but raises a Rewrite.Error
exception in case
of an error.
Updates the source for the given path
and key
with the given fun
.
The same as update_source/5
but raises a Rewrite.Error
exception in case
of an error.
Returns true
if any source in the rewrite
project returns true
for
Source.updated?/1
.
Writes a source to disk.
The same as write/3
but raises an exception in case of an error.
Writes all sources in the rewrite
project to disk.
Types
@type by() :: module()
@type key() :: atom()
@type opts() :: keyword()
@type wildcard() :: IO.chardata()
Functions
@spec count(t(), String.t()) :: non_neg_integer()
Counts the sources with the given extname
in the rewrite
project.
@spec create_source(t(), Path.t() | nil, String.t(), opts()) :: Rewrite.Source.t()
Creates a new %Source{}
without putting it to the %Rewrite{}
project.
The :filetypes
option of the project is used to create the source. If
options have been specified for the file type, the given options will be
merged into those options. If no path
is given, the default file type is
created.
The function does not check whether the %Rewrite{}
project already has a
%Source{}
with the specified path.
Use new_source/4
if the source is to be inserted directly into the project.
Deletes the source for the given path
from the rewrite
.
The file system files are not removed, even if the project is written. Use
rm/2
or rm!/2
to delete a file and source.
If the source is not part of the rewrite
project the unchanged rewrite
is
returned.
Examples
iex> {:ok, project} = Rewrite.from_sources([
...> Source.from_string(":a", path: "a.exs"),
...> Source.from_string(":b", path: "b.exs"),
...> Source.from_string(":a", path: "c.exs")
...> ])
iex> Rewrite.paths(project)
["a.exs", "b.exs", "c.exs"]
iex> project = Rewrite.delete(project, "a.exs")
iex> Rewrite.paths(project)
["b.exs", "c.exs"]
iex> project = Rewrite.delete(project, "b.exs")
iex> Rewrite.paths(project)
["c.exs"]
iex> project = Rewrite.delete(project, "b.exs")
iex> Rewrite.paths(project)
["c.exs"]
@spec dot_formatter(t()) :: Rewrite.DotFormatter.t()
Returns the DotFormatter
for the given rewrite
project.
When no formatter is set, the default formatter from
Rewrite.DotFormatter.default/0
is returned. A dot formatter can be set with
dot_formatter/2
.
@spec dot_formatter(t(), Rewrite.DotFormatter.t() | nil) :: t()
Sets a dot_formatter
for the given rewrite
project.
Drops the sources with the given paths
from the rewrite
project.
The file system files are not removed, even if the project is written. Use
rm/2
or rm!/2
to delete a file and source.
If paths
contains paths that are not in rewrite
, they're simply ignored.
Examples
iex> {:ok, project} = Rewrite.from_sources([
...> Source.from_string(":a", path: "a.exs"),
...> Source.from_string(":b", path: "b.exs"),
...> Source.from_string(":a", path: "c.exs")
...> ])
iex> project = Rewrite.drop(project, ["a.exs", "b.exs", "z.exs"])
iex> Rewrite.paths(project)
["c.exs"]
Returns the extension of the given file
.
Formats the given rewrite
project with the given dot_formatter
.
Uses the formatter from dot_formatter/2
if no formatter ist set by
:dot_formatter
in the options. The other options are the same as for
DotFormatter.read!/2
.
The same as format/2
but raises an exception in case of an error.
Formats a source in a rewrite
project.
Uses the formatter from dot_formatter/2
if no formatter ist set by
:dot_formatter
in the options. The other options are the same as for
Code.format_string!/2
.
@spec format_source!(t(), Path.t() | Rewrite.Source.t(), keyword()) :: t()
The same as format_source/3
but raises an exception in case of an error.
@spec from_sources([Rewrite.Source.t()], opts()) :: {:ok, t()} | {:error, term()}
Creates a %Rewrite{}
from the given sources.
Returns {:ok, rewrite}
for a list of regular sources.
Returns {:error, error}
for sources with a missing path and/or duplicated
paths.
@spec from_sources!([Rewrite.Source.t()], opts()) :: t()
Same as from_sources/2
, but raises a Rewrite.Error
exception in case of
failure.
Returns true
when the %Rewrite{}
contains a %Source{}
with the given
path
.
Examples
iex> {:ok, project} = Rewrite.from_sources([
...> Source.from_string(":a", path: "a.exs")
...> ])
iex> Rewrite.has_source?(project, "a.exs")
true
iex> Rewrite.has_source?(project, "b.exs")
false
Returns true
if any source has one or more issues.
@spec map(t(), (Rewrite.Source.t() -> Rewrite.Source.t())) :: {:ok, t()} | {:error, [{:nosource | :overwrites | :nopath, Rewrite.Source.t()}]}
Invokes fun
for each source
in the rewrite
project and updates the
rewirte
project with the result of fun
.
Returns a {:ok, rewrite}
if any update is successful.
Returns {:error, errors, rewrite}
where rewrite
is updated for all sources
that are updated successful. The errors
are the errors
of update/3
.
@spec map!(t(), (Rewrite.Source.t() -> Rewrite.Source.t())) :: t()
Return a rewrite
project where each source
is the result of invoking
fun
on each source
of the given rewrite
project.
Moves a source from one path to another.
Same as move/4
, but raises an exception in case of failure.
Creates an empty project.
Options
:filetypes
- a list of modules implementing the behaviorRewrite.Filetype
. This list is used to add thefiletype
to thesources
of the corresponding files. The list can contain modules representing a file type or a tuple of{module(), keyword()}
. Rewrite uses the keyword list from the tuple as the options argument when a file is read.Defaults to
[Rewrite.Source, Rewrite.Source.Ex]
.:dot_formatter
- a%DotFormatter{}
that is used to format sources. To get and update a dot formatter seedot_formatter/2
and to create one seeRewrite.DotFormatter
.
Examples
iex> project = Rewrite.new()
iex> path = "test/fixtures/source/hello.txt"
iex> project = Rewrite.read!(project, path)
iex> project |> Rewrite.source!(path) |> Source.get(:content)
"hello\n"
iex> project |> Rewrite.source!(path) |> Source.owner()
Rewrite
iex> project = Rewrite.new(filetypes: [{Rewrite.Source, owner: MyApp}])
iex> path = "test/fixtures/source/hello.txt"
iex> project = Rewrite.read!(project, path)
iex> project |> Rewrite.source!(path) |> Source.owner()
MyApp
Creates a %Rewrite{}
from the given inputs
.
Accepts the same options as new/1
.
Creates a new %Source{}
and puts the source to the %Rewrite{}
project.
The :filetypes
option of the project is used to create the source. If
options have been specified for the file type, the given options will be
merged into those options.
Use create_source/4
if the source is not to be inserted directly into the
project.
Same as new_source/4
, but raises a Rewrite.Error
exception in case of failure.
Returns a sorted list of all paths in the rewrite
project.
@spec put(t(), Rewrite.Source.t()) :: {:ok, t()} | {:error, Rewrite.Error.t()}
Puts the given source
to the given rewrite
project.
Returns {:ok, rewrite}
if successful, {:error, reason}
otherwise.
Examples
iex> project = Rewrite.new()
iex> {:ok, project} = Rewrite.put(project, Source.from_string(":a", path: "a.exs"))
iex> map_size(project.sources)
1
iex> Rewrite.put(project, Source.from_string(":b"))
{:error, %Rewrite.Error{reason: :nopath}}
iex> Rewrite.put(project, Source.from_string(":a", path: "a.exs"))
{:error, %Rewrite.Error{reason: :overwrites, path: "a.exs"}}
@spec put!(t(), Rewrite.Source.t()) :: t()
Same as put/2
, but raises a Rewrite.Error
exception in case of failure.
Reads the given input
/inputs
and adds the source/sources to the project
when not already readed.
Options
:force
, default:false
- forces the reading of sources. Withforce: true
updates and issues for an already existing source are deleted.
@spec rm(t(), Rewrite.Source.t() | Path.t()) :: {:ok, t()} | {:error, Rewrite.Error.t() | Rewrite.SourceError.t()}
Tries to delete the source
file in the file system and removes the source
from the rewrite
project.
Returns {:ok, rewrite}
if successful, or {:error, error}
if an error
occurs.
Note the file is deleted even if in read-only mode.
@spec rm!(t(), Rewrite.Source.t() | Path.t()) :: t()
Same as source/2
, but raises a Rewrite.Error
exception in case of failure.
@spec source(t(), Path.t()) :: {:ok, Rewrite.Source.t()} | {:error, Rewrite.Error.t()}
Returns the %Rewrite.Source{}
for the given path
.
Returns an :ok
tuple with the found source, if not exactly one source is
available an :error
is returned.
See also sources/2
to get a list of sources for a given path
.
@spec source!(t(), Path.t()) :: Rewrite.Source.t()
Same as source/2
, but raises a Rewrite.Error
exception in case of
failure.
@spec sources(t()) :: [Rewrite.Source.t()]
Returns all sources sorted by path.
@spec update(t(), Rewrite.Source.t()) :: {:ok, t()} | {:error, Rewrite.Error.t()}
Updates the given source
in the rewrite
project.
This function will be usually used if the path
for the source
has not
changed.
Returns {:ok, rewrite}
if successful, {:error, error}
otherwise.
@spec update(t(), Path.t(), Rewrite.Source.t() | function()) :: {:ok, t()} | {:error, Rewrite.Error.t() | Rewrite.UpdateError.t()}
Updates a source for the given path
in the rewrite
project.
If source
a Rewrite.Source
struct the struct is used to update the
rewrite
project.
If source
is a function the source for the given path
is passed to the
function and the result is used to update the rewrite
project.
Returns {:ok, rewrite}
if the update was successful, {:error, error}
otherwise.
Examples
iex> a = Source.Ex.from_string(":a", path: "a.exs")
iex> b = Source.Ex.from_string(":b", path: "b.exs")
iex> {:ok, project} = Rewrite.from_sources([a, b])
iex> {:ok, project} = Rewrite.update(project, "a.exs", Source.Ex.from_string(":foo", path: "a.exs"))
iex> project |> Rewrite.source!("a.exs") |> Source.get(:content)
":foo"
iex> {:ok, project} = Rewrite.update(project, "a.exs", fn s -> Source.update(s, :content, ":baz") end)
iex> project |> Rewrite.source!("a.exs") |> Source.get(:content)
":baz"
iex> {:ok, project} = Rewrite.update(project, "a.exs", fn s -> Source.update(s, :path, "c.exs") end)
iex> Rewrite.paths(project)
["b.exs", "c.exs"]
iex> Rewrite.update(project, "no.exs", Source.from_string(":foo", path: "x.exs"))
{:error, %Rewrite.Error{reason: :nosource, path: "no.exs"}}
iex> Rewrite.update(project, "c.exs", Source.from_string(":foo"))
{:error, %Rewrite.UpdateError{reason: :nopath, source: "c.exs"}}
iex> Rewrite.update(project, "c.exs", fn _ -> b end)
{:error, %Rewrite.UpdateError{reason: :overwrites, path: "b.exs", source: "c.exs"}}
@spec update!(t(), Rewrite.Source.t()) :: t()
The same as update/2
but raises a Rewrite.Error
exception in case
of an error.
@spec update!(t(), Path.t(), Rewrite.Source.t() | function()) :: t()
The same as update/3
but raises a Rewrite.Error
exception in case
of an error.
Updates the source for the given path
and key
with the given fun
.
The function combines update/3
and Source.update/4
in one call.
Examples
iex> project =
...> Rewrite.new()
...> |> Rewrite.new_source!("test.md", "foo")
...> |> Rewrite.update_source!("test.md", :content, fn content ->
...> content <> "bar"
...> end)
...> |> Rewrite.update_source!("test.md", :content, &String.upcase/1, by: MyApp)
iex> source = Rewrite.source!(project, "test.md")
iex> source.content
"FOOBAR"
iex> source.history
[{:content, MyApp, "foobar"}, {:content, Rewrite, "foo"}]
The same as update_source/5
but raises a Rewrite.Error
exception in case
of an error.
Returns true
if any source in the rewrite
project returns true
for
Source.updated?/1
.
Examples
iex> {:ok, project} = Rewrite.from_sources([
...> Source.Ex.from_string(":a", path: "a.exs"),
...> Source.Ex.from_string(":b", path: "b.exs"),
...> Source.Ex.from_string("c", path: "c.txt")
...> ])
iex> Rewrite.updated?(project)
false
iex> project = Rewrite.update!(project, "a.exs", fn source ->
...> Source.update(source, :quoted, ":z")
...> end)
iex> Rewrite.updated?(project)
true
@spec write(t(), Path.t() | Rewrite.Source.t(), nil | :force) :: {:ok, t()} | {:error, Rewrite.Error.t() | Rewrite.SourceError.t()}
Writes a source to disk.
The function expects a path or a %Source{}
as first argument.
Returns {:ok, rewrite}
if the file was written successful. See also
Source.write/2
.
If the given source
is not part of the rewrite
project then it is added.
@spec write!(t(), Path.t() | Rewrite.Source.t(), nil | :force) :: t()
The same as write/3
but raises an exception in case of an error.
@spec write_all(t(), opts()) :: {:ok, t()} | {:error, [Rewrite.SourceError.t()], t()}
Writes all sources in the rewrite
project to disk.
This function calls Rewrite.Source.write/1
on all sources in the rewrite
project.
Returns {:ok, rewrite}
if all sources are written successfully.
Returns {:error, reasons, rewrite}
where rewrite
is updated for all
sources that are written successfully.
Options
exclude
- a list paths to exclude form writting.force
, default:false
- forces the writting of unchanged files.