View Source Rewrite.Source (rewrite v0.9.0)
A representation of some source in a project.
The %Source{}
contains the content
of the file given by path
. The module
contains update/3
to update the path
and/or the content
. The changes are
recorded in the history
list.
The struct also holds issues
for the source.
The different versions of content
and path
are available via get/3
.
A source is extensible via filetype
, see Rewrite.Filetype
.
Summary
Types
The version
of a %Source{}
. The version 1
indicates that the source has
no changes.
Functions
Adds the given issue
to the source
.
Adds the given issues
to the source
.
Returns iodata showing all diffs of the given source
.
Returns true
if the file has been modified since it was read.
Sets the filetype
for the source
.
Returns true when from
matches to value for key :from
.
Creates a new %Source{}
from the given string
.
Gets the value for :content
, :path
in source
or a specific key
in
filetype
.
Gets the value for :content
, :path
in source
or a specific key
in
filetype
for the given version
.
Returns true
if the source
has issues for the given version
.
Calculates the current hash from the given source
.
Returns all issues of the given source
.
Returns the owner of the given source
.
Assigns a private key
and value
to the source
.
Creates a new %Source{}
from the given path
.
Tries to delete the file source
.
Same as rm/1
, but raises a Rewrite.SourceError
exception in case of
failure. Otherwise :ok
.
Undoes the given number
of changes.
Updates the content
or the path
of a source
.
Returns true
if the source was updated.
Returns the version
of the given source
. The value 1
indicates that the
source has no changes.
Writes the source to disk.
Same as write/1
, but raises a Rewrite.SourceError
exception in case of
failure.
Types
@type by() :: module()
@type content() :: String.t()
@type extension() :: String.t()
@type filetype() :: map()
@type from() :: :file | :string
@type issue() :: any()
@type key() :: atom()
@type kind() :: :content | :path
@type opts() :: keyword()
@type owner() :: module()
@type value() :: any()
@type version() :: pos_integer()
The version
of a %Source{}
. The version 1
indicates that the source has
no changes.
Functions
Adds the given issue
to the source
.
Adds the given issues
to the source
.
Returns iodata showing all diffs of the given source
.
See Rewrite.TextDiff.format/3
for options.
Examples
iex> code = """
...> def foo( x ) do
...> {:x,
...> x}
...> end
...> """
iex> formatted = code |> Code.format_string!() |> IO.iodata_to_binary()
iex> source = Source.Ex.from_string(code)
iex> source |> Source.diff() |> IO.iodata_to_binary()
""
iex> source
...> |> Source.update(:content, formatted)
...> |> Source.diff(color: false)
...> |> IO.iodata_to_binary()
"""
1 - |def foo( x ) do
2 - | {:x,
3 - | x}
1 + |def foo(x) do
2 + | {:x, x}
4 3 |end
5 4 |
"""
Returns true
if the file has been modified since it was read.
If the key :from
does not contain :file
the function returns false
.
Examples
iex> File.write("tmp/hello.txt", "hello")
iex> source = Source.read!("tmp/hello.txt")
iex> Source.file_changed?(source)
false
iex> File.write("tmp/hello.txt", "Hello, world!")
iex> Source.file_changed?(source)
true
iex> source = Source.update(source, :path, nil)
iex> Source.file_changed?(source)
true
iex> File.write("tmp/hello.txt", "hello")
iex> Source.file_changed?(source)
false
iex> File.rm!("tmp/hello.txt")
iex> Source.file_changed?(source)
true
iex> source = Source.from_string("hello")
iex> Source.file_changed?(source)
false
Sets the filetype
for the source
.
Returns true when from
matches to value for key :from
.
Examples
iex> source = Source.from_string("hello")
iex> Source.from?(source, :file)
false
iex> Source.from?(source, :string)
true
Creates a new %Source{}
from the given string
.
Examples
iex> source = Source.from_string("hello")
iex> source.content
"hello"
Gets the value for :content
, :path
in source
or a specific key
in
filetype
.
Raises Rewrite.SourceKeyError
if the key
can't be found.
Gets the value for :content
, :path
in source
or a specific key
in
filetype
for the given version
.
Raises Rewrite.SourceKeyError
if the key
can't be found.
Examples
iex> bar =
...> """
...> defmodule Bar do
...> def bar, do: :bar
...> end
...> """
iex> foo =
...> """
...> defmodule Foo do
...> def foo, do: :foo
...> end
...> """
iex> source = Source.Ex.from_string(bar)
iex> source = Source.update(source, :content, foo)
iex> Source.get(source, :content) == foo
true
iex> Source.get(source, :content, 2) == foo
true
iex> Source.get(source, :content, 1) == bar
true
iex> source =
...> "hello"
...> |> Source.from_string("some/where/hello.txt")
...> |> Source.update(:path, "some/where/else/hello.txt")
...> Source.get(source, :path, 1)
"some/where/hello.txt"
iex> Source.get(source, :path, 2)
"some/where/else/hello.txt"
Returns true
if the source
has issues for the given version
.
The version
argument also accepts :actual
and :all
to check whether the
source
has problems for the actual version or if there are problems at all.
Examples
iex> source =
...> "a + b"
...> |> Source.Ex.from_string("some/where/plus.exs")
...> |> Source.add_issue(%{issue: :foo})
...> |> Source.update(:path, "some/where/else/plus.exs")
...> |> Source.add_issue(%{issue: :bar})
iex> Source.has_issues?(source)
true
iex> Source.has_issues?(source, 1)
true
iex> Source.has_issues?(source, :all)
true
iex> source = Source.update(source, :content, "a - b")
iex> Source.has_issues?(source)
false
iex> Source.has_issues?(source, 2)
true
iex> Source.has_issues?(source, :all)
true
Calculates the current hash from the given source
.
Examples
iex> source = Source.from_string("""
...> defmodule Foo do
...> def bar, do: :bar
...> end
...> """)
iex> Source.hash(source)
<<76, 24, 5, 252, 117, 230, 0, 217, 129, 150, 68, 248, 6, 48, 72, 46>>
Returns all issues of the given source
.
Returns the owner of the given source
.
Assigns a private key
and value
to the source
.
This is not used or accessed by Rewrite, but is intended as private storage for users or libraries that wish to store additional data about a source.
Examples
iex> source =
...> "a + b"
...> |> Source.from_string()
...> |> Source.put_private(:origin, :example)
iex> source.private[:origin]
:example
Creates a new %Source{}
from the given path
.
Examples
iex> source = Source.read!("test/fixtures/source/hello.txt")
iex> source.content
"""
hello
"""
@spec rm(t()) :: :ok | {:error, Rewrite.SourceError.t()}
Tries to delete the file source
.
Returns :ok
if successful, or {:error, reason}
if an error occurs.
Note the file is deleted even if in read-only mode.
@spec rm!(t()) :: :ok
Same as rm/1
, but raises a Rewrite.SourceError
exception in case of
failure. Otherwise :ok
.
@spec undo(t(), non_neg_integer()) :: t()
Undoes the given number
of changes.
Examples
iex> a = Source.from_string("test-a", "test/foo.txt")
iex> b = Source.update(a, :content, "test-b")
iex> c = Source.update(b, :path, "test/bar.txt")
iex> d = Source.update(c, :content, "test-d")
iex> d |> Source.undo() |> Source.get(:content)
"test-b"
iex> d |> Source.undo(1) |> Source.get(:content)
"test-b"
iex> d |> Source.undo(2) |> Source.get(:path)
"test/foo.txt"
iex> d |> Source.undo(3) |> Source.get(:content)
"test-a"
iex> d |> Source.undo(9) |> Source.get(:content)
"test-a"
iex> d |> Source.undo(9) |> Source.updated?()
false
iex> d |> Source.undo(-9) |> Source.get(:content)
"test-d"
Updates the content
or the path
of a source
.
Examples
iex> source =
...> "foo"
...> |> Source.from_string()
...> |> Source.update(Example, :path, "test/fixtures/new.exs")
...> |> Source.update(:content, "bar")
iex> source.history
[{:content, Rewrite, "foo"}, {:path, Example, nil}]
iex> source.content
"bar"
If the new value is equal to the current value, no history will be added.
iex> source =
...> "42"
...> |> Source.from_string()
...> |> Source.update(Example, :content, "21")
...> |> Source.update(Example, :content, "21")
...> |> Source.update(Example, :content, "21")
iex> source.history
[{:content, Example, "42"}]
Returns true
if the source was updated.
The optional argument kind
specifies whether only :code
changes or :path
changes are considered. Defaults to :any
.
Examples
iex> source = Source.from_string("foo")
iex> Source.updated?(source)
false
iex> source = Source.update(source, :content, "bar")
iex> Source.updated?(source)
true
iex> Source.updated?(source, :path)
false
iex> Source.updated?(source, :content)
true
Returns the version
of the given source
. The value 1
indicates that the
source has no changes.
@spec write(t(), opts()) :: {:ok, t()} | {:error, Rewrite.SourceError.t()}
Writes the source to disk.
Returns {:ok, source}
when the file was written successfully. The returned
source
does not include any previous changes or issues.
If there's an error, this function returns {:error, error}
where error
is a Rewrite.SourceError
. You can raise it manually with raise/1
.
Returns {:error, error}
with reason: :nopath
if the current path
is nil.
Returns {:error, error}
with reason: :changed
if the file was changed
since reading. See also file_changed?/1
. The option force: true
forces
overwriting a changed file.
If the source :path
was updated then the old file will be deleted.
Missing directories are created.
Options
:force
, default:false
- forces the saving to overwrite changed files.:rm
, default:true
- prevents file deletion when set tofalse
.
Examples
iex> ":test" |> Source.from_string() |> Source.write()
{:error, %SourceError{reason: :nopath, path: nil, action: :write}}
iex> path = "tmp/foo.txt"
iex> File.write(path, "foo")
iex> source = path |> Source.read!() |> Source.update(:content, "bar")
iex> Source.updated?(source)
true
iex> {:ok, source} = Source.write(source)
iex> File.read(path)
{:ok, "bar\n"}
iex> Source.updated?(source)
false
iex> source = Source.from_string("bar")
iex> Source.write(source)
{:error, %SourceError{reason: :nopath, path: nil, action: :write}}
iex> source |> Source.update(:path, "tmp/bar.txt") |> Source.write()
iex> File.read("tmp/bar.txt")
{:ok, "bar\n"}
iex> path = "tmp/ping.txt"
iex> File.write(path, "ping")
iex> source = Source.read!(path)
iex> new_path = "tmp/pong.ex"
iex> source = Source.update(source, :path, new_path)
iex> Source.write(source)
iex> File.exists?(path)
false
iex> File.read(new_path)
{:ok, "ping\n"}
iex> path = "tmp/ping.txt"
iex> File.write(path, "ping")
iex> source = Source.read!(path)
iex> new_path = "tmp/pong.ex"
iex> source = Source.update(source, :path, new_path)
iex> Source.write(source, rm: false)
iex> File.exists?(path)
true
iex> path = "tmp/ping.txt"
iex> File.write(path, "ping")
iex> source = path |> Source.read!() |> Source.update(:content, "peng")
iex> File.write(path, "pong")
iex> Source.write(source)
{:error, %SourceError{reason: :changed, path: "tmp/ping.txt", action: :write}}
iex> {:ok, _source} = Source.write(source, force: true)
Same as write/1
, but raises a Rewrite.SourceError
exception in case of
failure.