StructyRecord (StructyRecord v0.2.1) View Source
StructyRecord provides a Struct-like interface for your Records.
- 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
:etstables.
Link to this section Summary
Link to this section Functions
Defines a module named alias that is also a Record composed of fields.
Parameters
aliasis the name of the module being defined. It also serves as thetagparameter ofRecord.defrecord/3, which helps identify the record.fieldsspecifies the shape of the record being defined. It is either:do_blockis 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/1to check if argument loosely matches this record's shape
Macros (available at compile time):
{}/0to create a new record with default values for all fields{}/1to create a new record with the given fields and values{}/1to get the zero-based index of the given field in a record{{}}/1to convert a record into a list of its fields and values{{}}/2to get the value of a given field in a given record{{}}/2to assign the given fields and values in a given recordrecord?/1to check if argument strictly matches this record's shaperecord/0to create a new record with default values for all fieldsrecord/1to create a new record with the given fields and valuesrecord/1to get the zero-based index of the given field in a recordrecord/1to convert a record into a list of its fields and valuesrecord/2to get the value of a given field in a given recordrecord/2to assign the given fields and values in a given recordget/2to fetch the value of a given field in a given recordput/2to assign the given fields and values inside a given recordget_${field}/1to fetch the value of a specific field in a given recordput_${field}/2to assign the value of a specific field in a given recordindex/1to get the zero-based index of the given field in a recordkeypos/1to get the 1-based index of the given field in a recordto_list/0to get a template of fields and default values for this recordto_list/1to convert a record into a list of its fields and values
Functions (available at runtime only):
from_list/1to create a new record with the given fields and valuesmerge/2to assign the given fields and values inside a given recordinspect/2to inspect the contents of a record usingKernel.inspect/2
Examples
Activate this macro in your environment:
require StructyRecordDefine 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
endActivate its macros in your environment:
use RectangleCreate 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() #-> 25Set 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