BeamPatch (beam_patch v0.2.0)
View SourcePatch Elixir & Erlang modules at runtime
Example
iex> require BeamPatch
iex>
iex> String.jaro_distance("same", "same")
1.0
iex> BeamPatch.patch_and_load! String do
...> @modifier 2
...>
...> @override original: [rename_to: :jaro_distance_orig]
...> def jaro_distance(a, b), do: jaro_distance_orig(a, b) * @modifier
...> end
iex>
iex> String.jaro_distance("same", "same")
2.0
Changing function visibility
iex> BeamPatch.patch_and_load! String do
...> # Rename the original and make it public
...> @override original: [rename_to: :jaro_distance_orig, export?: true]
...> # As expected, `defp` keyword makes `jaro_distance/2` private
...> defp jaro_distance(a, b), do: jaro_distance_orig(a, b) * 2
...>
...> # Define a completely new function as a part of `String`'s interface
...> def my_jaro_distance(a, b),
...> do: jaro_distance(a, b) * jaro_distance_orig(a, b)
...> end
iex>
iex> function_exported?(String, :jaro_distance, 2)
false
iex> String.jaro_distance_orig("same", "same")
1.0
iex> String.my_jaro_distance("same", "same")
2.0
Split patching and loading
defmodule CompileTimePatch do
# A common pattern is patching at compilation time,
# but loading the patched module at runtime
@patch BeamPatch.patch_quoted!(
String,
quote do
def hello, do: :world
end
)
def load, do: BeamPatch.load!(@patch)
end
iex> CompileTimePatch.load()
iex> String.hello()
:world
Installation
def deps do
[
{:beam_patch, "~> 0.2.0"}
]
end
Summary
Functions
Load a patched module.
Load a patched module.
Patch (without loading) a module with body given via do end
block.
Patch and load a module with body given via do end
block.
Patch a module with a quoted body.
Patch a module with a quoted body.
Patch and load a module with a quoted body.
Patch and load a module with a quoted body.
Functions
@spec load(BeamPatch.Patch.t()) :: :ok | {:error, BeamPatch.Error.t()}
Load a patched module.
@spec load!(BeamPatch.Patch.t()) :: :ok
Load a patched module.
Raises BeamPatch.ModuleLoadError.t/0
on error.
Patch (without loading) a module with body given via do end
block.
This is sugar for patch_quoted!/2
function.
Raises one of BeamPatch.Error.t/0
on error.
Patch and load a module with body given via do end
block.
This is sugar for patch_quoted_and_load!/2
function.
Raises one of BeamPatch.Error.t/0
on error.
@spec patch_quoted(module(), bytecode :: binary() | nil, body :: Macro.t()) :: {:ok, BeamPatch.Patch.t()} | {:error, BeamPatch.Error.t()}
Patch a module with a quoted body.
@spec patch_quoted!(module(), bytecode :: binary() | nil, body :: Macro.t()) :: BeamPatch.Patch.t()
Patch a module with a quoted body.
Raises one of BeamPatch.Error.t/0
on error.
@spec patch_quoted_and_load(module(), bytecode :: binary() | nil, body :: Macro.t()) :: {:ok, BeamPatch.Patch.t()} | {:error, BeamPatch.Error.t()}
Patch and load a module with a quoted body.
Patch and load a module with a quoted body.
Raises one of BeamPatch.Error.t/0
on error.