View Source Rewrite.Source (rewrite v0.10.5)
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.