Module smerl
Copyright © 2006-2007, 2016 AUTHORS Smerl is an Erlang library that simplifies the creation and manipulation of Erlang modules in runtime. You don't need to know Smerl in order to use ErlyWeb; Smerl is included in ErlyWeb because ErlyWeb uses it internally. Smerl uses Erlang's capabilities for hot code swapping and abstract syntax tree transformations to do its magic. Smerl is inspired by the rdbms_codegen.erl module in the RDBMS application written by Ulf Wiger. RDBMS is part of Jungerl ([http://jungerl.sf.net]). Here's a quick example illustrating how to use Smerl: ``` test_smerl() -> M1 = smerl:new(foo), {ok, M2} = smerl:add_func(M1, "bar() -> 1 + 1."), smerl:compile(M2), foo:bar(), % returns 2`` smerl:has_func(M2, bar, 0). % returns true ''' New functions can be expressed either as strings of Erlang code or as abstract forms. For more information, read the Abstract Format section in the ERTS User's guide ([http://erlang.org/doc/doc-5.5/erts-5.5/doc/html/absform.html#4]). Using the abstract format, the 3rd line of the above example would be written as ``` {ok,M2} = smerl:add_func(M1, {function,1,bar,0, [{clause,1,[],[], [{op,1,'+',{integer,1,1},{integer,1,1}}]}]). ''' <p>The abstact format may look more verbose in this example, but it's also easier to manipulate in code.</p>
Authors: Yariv Sadan.
Description
Simple Metaprogramming for ErlangData Types
args()
args() = term() | [term()]
error_t()
error_t(Error) = ok | {error, Error}
export()
export() = {Function :: atom(), Arity :: arity()}
exports()
exports() = [export()]
A list of export()
s.
func_form()
func_form() = erl_parse:abstract_form()
The abstract form for the function, as described in the ERTS Users' manual.
func_forms()
func_forms() = [func_form()]
A list of func_form()
s.
meta_mod()
meta_mod() =
#meta_mod{module = module(),
file = undefined | file:filename(),
exports = exports(),
forms = func_forms(),
export_all = boolean()}
A data structure holding the abstract representation for a module.
ok_t()
ok_t(Value) = {ok, Value} | error
result()
result(Value, Error) = {ok, Value} | {error, Error}
result()
result(Value) = result(Value, term())
Function Index
add_func/2 | Add a new exported function to MetaMod . |
add_func/3 | Add Function to MetaMod and return the new meta_mod() . |
compile/1 | Compile MetaMod and load the resulting BEAM into the emulator. |
compile/2 | Compile MetaMod and load the resulting BEAM into the emulator. |
curry/2 | Get the curried form for Form with Args . |
curry/4 | Curry Module :Function /Arity with the given Args . |
curry/5 | Curry Module :Function /Arity with the given Args ,
renaming it to NewName and return the renamed form. |
curry_add/3 | Add Form curried with Args to MetaMod . |
curry_add/4 | Add Function /Arity curried with Args to MetaMod . |
curry_add/5 | Curry MetaMod :Function /Arity and add it to MetaMod as NewName . |
curry_add/6 | Curry Module :Function /Arity and add it to MetaMod as NewName . |
curry_replace/3 | Replace the function represented by Form in MetaMod
with its curried form. |
curry_replace/4 | Replace Function /Arity in MetaMod with its curried form. |
embed_all/2 | Apply embed_args/2 with Values to all forms in MetaMod . |
embed_args/2 | Replace the arguments of the function represented by Form ,
where the argument's Name matches an element from Vals
with the corresponding Value . |
embed_args/4 | Equivalent to embed_args(MetaMod, Name, Arity, Values, Name). |
embed_args/5 | Apply embed_args/2 to MetaMod :Function /Arity and
add the resulting function to MetMod , after renaming it to NewName . |
extend/2 | Add aliases for Parent 's functions missing from Child to Child . |
extend/3 | Similar to extend/2 , with the addition of ArityDiff , which
indicates the difference in arities Smerl should use when figuring
out which functions to generate based on the modules' exports. |
extend/4 | |
for_file/1 | Equivalent to for_file(SrcFilePath, []). |
for_file/2 | Equivalent to for_file(SrcFilePath, IncludePaths, []). |
for_file/3 | Create a meta_mod for a module from its source file. |
for_module/1 | Equivalent to for_module(ModuleName, []). |
for_module/2 | Equivalent to for_module(ModuleName, IncludePaths, []). |
for_module/3 | Create a meta_mod tuple for an existing module. |
get_attribute/2 | Get the value of MetaMod 's Key attribute. |
get_export_all/1 | Get the export_all value for MetaMod . |
get_exports/1 | Return the list of exports in the meta_mod. |
get_forms/1 | Return the list of function forms in the meta_mod. |
get_func/3 | Attempt to get the func_form() for MetaMod :Function /Arity . |
get_module/1 | Return the module name for the meta_mod. |
has_func/3 | Check whether MetaMod has a function Function /Arity . |
new/1 | Create a new meta_mod for a module with the given name. |
remove_export/3 | Remove an export {Function, Arity}
from the list of exports in MetaMod . |
remove_func/3 | Try to remove Function from MetaMod . |
rename/2 | Change the name of the function represented by Form to NewName . |
replace_func/2 | Replace an existing function with a new one. |
set_export_all/2 | Set the export_all value for MetaMod . |
set_exports/2 | Set the MetaMod 's export list to Exports . |
set_forms/2 | |
set_module/2 | Set the meta_mod's module name. |
to_src/1 | Return the pretty-printed source code for MetaMod . |
to_src/2 | Equivalent to file:write_file(Filename, to_src(MetaMod)). |
Function Details
add_func/2
add_func(MetaMod, Form) -> result(meta_mod(), parse_error)
MetaMod = meta_mod()
Form = func_form() | string()
Equivalent to add_func(MetaMod, Form, true).
Add a new exported function to MetaMod
.
add_func/3
add_func(MetaMod, Func, Export) -> result(meta_mod(), parse_error)
MetaMod = meta_mod()
Func = func_form() | string()
Export = boolean()
Add Function
to MetaMod
and return the new meta_mod()
. If
Export
is true
, add Function
to MetaMod
's exports
.
compile/1
compile(MetaMod :: meta_mod()) -> error_t(term())
Equivalent to compile(MetaMod, []).
Compile MetaMod
and load the resulting BEAM into the emulator.
compile/2
Equivalent to compile(MetaMod, [report_errprs, report_warnings, return_errors]).
Compile MetaMod
and load the resulting BEAM into the emulator.
Options
is a list of options as described in the compile
module in the
Erlang documentation.
If an outdir
is provided, write the .beam
file to it.
curry/2
curry(Form :: func_form(), Args :: args()) -> result(func_form())
Get the curried form for Form
with Args
.
Here, "currying" involves replacing one or more of the function's leading
arguments with predefined values.
curry/4
curry(Module, Function, Arity, Args) -> result(func_form())
Module = module() | meta_mod()
Function = atom()
Arity = arity()
Args = args()
Curry Module
:Function
/Arity
with the given Args
.
curry/5
curry(Module, Function, Arity, Args, NewName) ->
result(func_form())
Module = module() | meta_mod()
Function = atom()
Arity = arity()
Args = args()
NewName = atom()
Curry Module
:Function
/Arity
with the given Args
,
renaming it to NewName
and return the renamed form.
curry_add/3
curry_add(MetaMod, Form, Args) -> result(meta_mod())
MetaMod = meta_mod()
Form = func_form()
Args = args()
Add Form
curried with Args
to MetaMod
.
curry_add/4
curry_add(MetaMod, Function, Arity, Args) -> result(meta_mod())
MetaMod = meta_mod()
Function = atom()
Arity = arity()
Args = args()
Add Function
/Arity
curried with Args
to MetaMod
.
curry_add/5
curry_add(MetaMod, Function, Arity, Args, NewName) -> Result
MetaMod = meta_mod()
Function = atom()
Arity = arity()
Args = args()
NewName = atom()
Result = result(meta_mod(), parse_error)
Curry MetaMod
:Function
/Arity
and add it to MetaMod
as NewName
.
curry_add/6
curry_add(MetaMod, Module, Function, Arity, Args, NewName) ->
Result
MetaMod = meta_mod()
Module = module() | meta_mod()
Function = atom()
Arity = arity()
Args = args()
NewName = atom()
Result = result(meta_mod())
Curry Module
:Function
/Arity
and add it to MetaMod
as NewName
.
curry_replace/3
curry_replace(MetaMod, Form, Args) -> result(meta_mod())
MetaMod = meta_mod()
Form = func_form()
Args = args()
Replace the function represented by Form
in MetaMod
with its curried form.
curry_replace/4
curry_replace(MetaMod, Function, Arity, Args) ->
result(meta_mod())
MetaMod = meta_mod()
Function = atom()
Arity = arity()
Args = args()
Replace Function
/Arity
in MetaMod
with its curried form.
embed_all/2
embed_all(MetaMod, Values) -> NewMod
MetaMod = meta_mod()
Values = [{Name :: atom(), Value :: term()}]
NewMod = meta_mod()
Apply embed_args/2
with Values
to all forms in MetaMod
.
exports
for functions whose arities change are preserved.
embed_args/2
embed_args(Form, Vals) -> NewForm
Form = func_form()
Vals = [{Name :: atom(), Value :: term()}]
NewForm = func_form()
Replace the arguments of the function represented by Form
,
where the argument's Name
matches an element from Vals
with the corresponding Value
.
embed_args/4
embed_args(MetaMod, Function, Arity, Values) -> result(meta_mod())
MetaMod = meta_mod()
Function = atom()
Arity = arity()
Values = proplists:proplist()
Equivalent to embed_args(MetaMod, Name, Arity, Values, Name).
embed_args/5
embed_args(MetaMod, Function, Arity, Values, NewName) -> Result
MetaMod = meta_mod()
Function = atom()
Arity = arity()
Values = proplists:proplist()
NewName = atom()
Result = result(meta_mod())
Apply embed_args/2
to MetaMod
:Function
/Arity
and
add the resulting function to MetMod
, after renaming it to NewName
.
See also: rename/2.
extend/2
extend(Parent, Child) -> NewChildMod
Parent = module() | meta_mod()
Child = module() | meta_mod()
NewChildMod = meta_mod()
Add aliases for Parent
's functions missing from Child
to Child
.
The new functions in Child
are shallow, i.e. they have the name and arity
of the corresponding functions in Parent
, but instead of implementing their
logic they call the Parent
functions.
extend/3
extend(Parent, Child, ArityDiff) -> NewChildMod
Parent = module() | meta_mod()
Child = module() | meta_mod()
ArityDiff = non_neg_integer()
NewChildMod = meta_mod()
Similar to extend/2
, with the addition of ArityDiff
, which
indicates the difference in arities Smerl should use when figuring
out which functions to generate based on the modules' exports. This is
sometimes useful when calling extend/3
followed by embed_all/2
.
extend/4
extend(Parent, Child, ArityDiff, Options) -> NewChildMod
Parent = module() | meta_mod()
Child = module() | meta_mod()
ArityDiff = non_neg_integer()
Options = [proplists:property()]
NewChildMod = meta_mod()
for_file/1
for_file(SrcFilePath) -> any()
Equivalent to for_file(SrcFilePath, []).
for_file/2
for_file(SrcFilePath, IncludePaths) -> any()
Equivalent to for_file(SrcFilePath, IncludePaths, []).
for_file/3
for_file(SrcFilePath, IncludePaths, Macros) -> Result
SrcFilePath = file:filename()
IncludePaths = [file:filename()]
Macros = [{module(), atom()}]
Result = result(meta_mod(), invalid_module)
Create a meta_mod for a module from its source file.
for_module/1
for_module(ModuleName) -> any()
Equivalent to for_module(ModuleName, []).
for_module/2
for_module(ModuleName, IncludePaths) -> any()
Equivalent to for_module(ModuleName, IncludePaths, []).
for_module/3
for_module(ModuleName, IncludePaths, Macros) -> result(meta_mod)
ModuleName = atom() | string()
IncludePaths = [string()]
Macros = [{atom(), term()}]
Create a meta_mod tuple for an existing module. If ModuleName is a
string, it is interpreted as a file name (this is the same as calling
for_file/3
). If ModuleName is an atom, Smerl attempts to
find its abstract represtation either from its source file or from
its .beam file directly (if it has been compiled with debug_info).
If the abstract representation can't be found, this function returns
an error.
IncludePaths
argument is used when ModuleName
is a file name.
get_attribute/2
get_attribute(MetaMod :: meta_mod(), Key :: atom()) ->
result(term())
Get the value of MetaMod
's Key
attribute.
get_export_all/1
get_export_all(MetaMod :: meta_mod()) -> boolean()
Get the export_all
value for MetaMod
.
get_exports/1
get_exports(MetaMod :: meta_mod()) -> exports()
Return the list of exports in the meta_mod.
get_forms/1
get_forms(MetaMod :: meta_mod()) -> func_forms()
Return the list of function forms in the meta_mod.
get_func/3
get_func(MetaMod, Function, Arity) -> result(func_form())
MetaMod = meta_mod() | module()
Function = atom()
Arity = arity()
Attempt to get the func_form()
for MetaMod
:Function
/Arity
.
get_module/1
get_module(MetaMod :: meta_mod()) -> module()
Return the module name for the meta_mod.
has_func/3
has_func(MetaMod, Function, Arity) -> boolean()
MetaMod = meta_mod()
Function = atom()
Arity = arity()
Check whether MetaMod
has a function Function
/Arity
.
new/1
new(Module :: module()) -> meta_mod()
Create a new meta_mod for a module with the given name.
remove_export/3
remove_export(MetaMod, Function, Arity) -> NewMod
MetaMod = meta_mod()
Function = atom()
Arity = arity()
NewMod = meta_mod()
Remove an export {Function, Arity}
from the list of exports
in MetaMod
.
remove_func/3
remove_func(MetaMod, Function, Arity) -> NewMod
MetaMod = meta_mod()
Function = atom()
Arity = arity()
NewMod = meta_mod()
Try to remove Function
from MetaMod
.
If the function exists, return the new meta_mod()
.
Otherwise, return MetaMod
.
rename/2
rename(Form :: func_form(), NewName :: atom()) -> func_form()
Change the name of the function represented by Form
to NewName
.
replace_func/2
replace_func(MetaMod, Function) -> result(meta_mod())
MetaMod = meta_mod()
Function = string() | func_form()
Replace an existing function with a new one. If a matching function
doesn't exist, add Function
to MetaMod
. This is tantamount to calling
remove_func/3
followed by add_func/2
.
set_export_all/2
Set the export_all
value for MetaMod
.
set_exports/2
Set the MetaMod
's export list to Exports
.
set_forms/2
set_module/2
Set the meta_mod's module name.
to_src/1
to_src(MetaMod :: meta_mod()) -> Source :: string()
Return the pretty-printed source code for MetaMod
.
to_src/2
Equivalent to file:write_file(Filename, to_src(MetaMod)).