Patch Elixir & Erlang modules at runtime
require BeamPatch
assert String.jaro_distance("same", "same") == 1.0
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
assert String.jaro_distance("same", "same") == 2.0BeamPatch.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
refute function_exported?(String, :jaro_distance, 2)
assert String.jaro_distance_orig("same", "same") == 1.0
assert String.my_jaro_distance("same", "same") == 2.0defmodule 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
CompileTimePatch.load()
assert String.hello() == :worlddef deps do
[
{:beam_patch, "~> 0.2.2"}
]
end