sunaku
StructyRecord - provides a Struct-like interface for Records
Hey folks,
I’m pleased to announce StructyRecord, my very first Elixir library! ![]()
- GitHub - GitHub - sunaku/structy_record: 🎩 Provides a Struct-like interface for Records · GitHub
- Hex.pm - structy_record | Hex
I created this library to improve the usability of Records (which are clunky to use in comparison to the first-class language support for Structs) because my performance-sensitive Elixir applications make heavy use of ETS tables that rely on Records for data representation.
I hope that it’s also useful to you, enjoy! ![]()
Cheers.
Readme
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.
To get started, see the documentation for StructyRecord.defrecord/3:
iex> h StructyRecord.defrecord
Features
The defined module provides the following guards, macros, and functions.
Guards:
is_record/1to check if argument loosely matches this record’s shape
Macros:
record?/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 the given record into aKeywordlistrecord/2to get the value of a given field in a given recordrecord/2to update an existing record with the given fields and values${field}/1to get the value of a specific field in a given record${field}/2to set the value of a specific field in a given recordkeypos/1to get the 1-based index of the given field in a record
Functions:
record!/1to create a new record at runtime with the given fields and valuesrecord!/2to update an existing record with the given fields and values
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
width(r) * 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.record() #-> {Rectangle, nil, nil}
no_h = Rectangle.record(width: 1) #-> {Rectangle, 1, nil}
no_w = Rectangle.record(height: 2) #-> {Rectangle, nil, 2}
wide = Rectangle.record(width: 10, height: 5) #-> {Rectangle, 10, 5}
tall = Rectangle.record(width: 4, height: 25) #-> {Rectangle, 4, 25}
even = Rectangle.record(width: 10, height: 10) #-> {Rectangle, 10, 10}
Get values of fields in those instances:
tall |> Rectangle.height() #-> 25
tall |> Rectangle.record(:height) #-> 25
Rectangle.record(height: h) = tall; h #-> 25
Set values of fields in those instances:
even |> Rectangle.width(1) #-> {Rectangle, 1, 10}
even |> Rectangle.record(width: 1) #-> {Rectangle, 1, 10}
even |> Rectangle.width(1) |> Rectangle.height(2) #-> {Rectangle, 1, 2}
even |> Rectangle.record(width: 1, 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
Most Liked
OvermindDL1
Now if only the Elixir built-in Protocol’s supported dispatch based on the first tuple element. ^.^;
Love records though!
sunaku
Version 0.2.0 (2021-02-18)
This release adds a convenient new shorthand syntax for the record() macro,
renames field accessors to prevent name collisions, clarifies docs, and more.
Incompatible:
-
Rename
record!/1function tofrom_list/1. -
Rename
record!/2function tomerge/2. -
Add
get_andput_prefix to field accessors.Field names can no longer conflict with defined macros & functions.
-
Don’t check argument types in Elixiry interface.
It broke simple macro expansion when used in case/function clauses.
Enhancements:
-
Add
Module.{_}syntax forModule.record(_). -
Add
inspect/2for friendlier inspection. -
Add
to_list/0to get record’s template. -
Add
to_list/1alias forrecord/1macro. -
Add
index/1to get field index in tuple. -
Add
get/2macro as an alias torecord/2. -
Add
put/2macro as an alias torecord/2. -
Define documentation for all macros and functions.
Housekeeping:
-
record?/1macro: only use pattern matching check. -
keypos/1macro: don’t call module being defined. -
mix.exs: drop application(); use
runtime: false.
Popular in Announcing
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









