StructyRecord (StructyRecord v0.2.0) View Source
StructyRecord
provides a Struct-like interface for your Record
s.
- Use your record's macros in the same module where it is defined!
- Access and update fields in your record through named macro calls.
- Create and update records at runtime (not limited to compile time).
- Calculate 1-based indexes to access record fields in
:ets
tables.
Link to this section Summary
Link to this section Functions
Defines a module named alias
that is also a Record
composed of fields
.
Parameters
alias
is the name of the module being defined. It also serves as thetag
parameter ofRecord.defrecord/3
, which helps identify the record.fields
specifies the shape of the record being defined. It is either:do_block
is an optional block of code that is passed intodefmodule/2
. It allows you to extend the module being defined with your own custom code, which has compile-time access to all the guards and macros described below.
Results
The defined module contains the following guards, macros, and functions.
Guards (available at compile time):
is_record/1
to check if argument loosely matches this record's shape
Macros (available at compile time):
{}/0
to create a new record with default values for all fields{}/1
to create a new record with the given fields and values{}/1
to get the zero-based index of the given field in a record{{}}/1
to convert a record into a list of its fields and values{{}}/2
to get the value of a given field in a given record{{}}/2
to assign the given fields and values in a given recordrecord?/1
to check if argument strictly matches this record's shaperecord/0
to create a new record with default values for all fieldsrecord/1
to create a new record with the given fields and valuesrecord/1
to get the zero-based index of the given field in a recordrecord/1
to convert a record into a list of its fields and valuesrecord/2
to get the value of a given field in a given recordrecord/2
to assign the given fields and values in a given recordget/2
to fetch the value of a given field in a given recordput/2
to assign the given fields and values inside a given recordget_${field}/1
to fetch the value of a specific field in a given recordput_${field}/2
to assign the value of a specific field in a given recordindex/1
to get the zero-based index of the given field in a recordkeypos/1
to get the 1-based index of the given field in a recordto_list/0
to get a template of fields and default values for this recordto_list/1
to convert a record into a list of its fields and values
Functions (available at runtime only):
from_list/1
to create a new record with the given fields and valuesmerge/2
to assign the given fields and values inside a given recordinspect/2
to inspect the contents of a record usingKernel.inspect/2
Examples
Activate this macro in your environment:
require StructyRecord
Define a structy record for a rectangle:
StructyRecord.defrecord Rectangle, [:width, :height] do
def area(r = record()) do
get_width(r) * get_height(r)
end
def perimeter(record(width: w, height: h)) do
2 * (w + h)
end
def square?(record(width: same, height: same)), do: true
def square?(_), do: false
end
Activate its macros in your environment:
use Rectangle
Create instances of your structy record:
rect = Rectangle.{} #-> {Rectangle, nil, nil}
rect = Rectangle.{[]} #-> {Rectangle, nil, nil}
no_h = Rectangle.{[width: 1]} #-> {Rectangle, 1, nil}
no_w = Rectangle.{[height: 2]} #-> {Rectangle, nil, 2}
wide = Rectangle.{[width: 10, height: 5]} #-> {Rectangle, 10, 5}
tall = Rectangle.{[width: 4, height: 25]} #-> {Rectangle, 4, 25}
even = Rectangle.{[width: 10, height: 10]} #-> {Rectangle, 10, 10}
Inspect the contents of those instances:
rect |> Rectangle.inspect() #-> "Rectangle.{[width: nil, height: nil]}"
no_h |> Rectangle.inspect() #-> "Rectangle.{[width: 1, height: nil]}"
no_w |> Rectangle.inspect() #-> "Rectangle.{[width: nil, height: 2]}"
wide |> Rectangle.inspect() #-> "Rectangle.{[width: 10, height: 5]}"
tall |> Rectangle.inspect() #-> "Rectangle.{[width: 4, height: 25]}"
even |> Rectangle.inspect() #-> "Rectangle.{[width: 10, height: 10]}"
Get values of fields in those instances:
Rectangle.{{tall, :height}} #-> 25
Rectangle.{[height: h]} = tall; h #-> 25
tall |> Rectangle.get_height() #-> 25
Set values of fields in those instances:
Rectangle.{{even, width: 1}} #-> {Rectangle, 1, 10}
even |> Rectangle.put(width: 1) #-> {Rectangle, 1, 10}
even |> Rectangle.put_width(1) #-> {Rectangle, 1, 10}
Rectangle.{{even, width: 1, height: 2}} #-> {Rectangle, 1, 2}
even |> Rectangle.put(width: 1, height: 2) #-> {Rectangle, 1, 2}
even |> Rectangle.put_width(1) |> Rectangle.put_height(2) #-> {Rectangle, 1, 2}
Use your custom code on those instances:
rect |> Rectangle.area() #-> (ArithmeticError) bad argument in arithmetic expression: nil * nil
no_h |> Rectangle.area() #-> (ArithmeticError) bad argument in arithmetic expression: 1 * nil
no_w |> Rectangle.area() #-> (ArithmeticError) bad argument in arithmetic expression: nil * 2
wide |> Rectangle.area() #-> 50
tall |> Rectangle.area() #-> 100
even |> Rectangle.area() #-> 100
rect |> Rectangle.perimeter() #-> (ArithmeticError) bad argument in arithmetic expression: nil + nil
no_h |> Rectangle.perimeter() #-> (ArithmeticError) bad argument in arithmetic expression: 1 + nil
no_w |> Rectangle.perimeter() #-> (ArithmeticError) bad argument in arithmetic expression: nil + 2
wide |> Rectangle.perimeter() #-> 30
tall |> Rectangle.perimeter() #-> 58
even |> Rectangle.perimeter() #-> 40
rect |> Rectangle.square?() #-> true
no_h |> Rectangle.square?() #-> false
no_w |> Rectangle.square?() #-> false
wide |> Rectangle.square?() #-> false
tall |> Rectangle.square?() #-> false
even |> Rectangle.square?() #-> true