An Elixir library implementing the FLOIP Expressions language.
iex(1)> Expression.evaluate!("Hello @name", %{
...(1)> "name" => "World"
...(1)> })
["Hello ", "World"]
iex(2)> Expression.evaluate("Hello @contact.name", %{
...(2)> "contact" => %{
...(2)> "name" => "peter"
...(2)> }
...(2)> })
{:ok, ["Hello ", "peter"]}
iex(6)> Expression.evaluate("Hello @contact.name, you were born in @(YEAR(contact.birthday))", %{
...(6)> "contact" => %{
...(6)> "name" => "mary",
...(6)> "birthday" => "1920-02-02T00:00:00"
...(6)> }
...(6)> })
{:ok, ["Hello ", "mary", ", you were born in ", 1920]}
iex(7)> Expression.evaluate("Hello @PROPER(contact.name)", %{
...(7)> "contact" => %{
...(7)> "name" => "peter rabbit"
...(7)> }
...(7)> })
{:ok, ["Hello ", "Peter Rabbit"]}
ex(8)> Expression.evaluate("Your next appointment is @(EDATE(contact.appointment, 1))", %{
...(8)> "contact" => %{
...(8)> "appointment" => DateTime.utc_now()
...(8)> }
...(8)> })
{:ok, ["Your next appointment is ", ~U[2022-06-25 08:39:51.730780Z]]}
iex(9)> Expression.evaluate("Your next appointment is @(DATEVALUE(EDATE(contact.appointment, 1), \"%Y-%m-%d\"))", %{
...(9)> "contact" => %{
...(9)> "appointment" => "2020-12-13T23:35:55"
...(9)> }
...(9)> })
{:ok, ["Your next appointment is ", "2021-01-13"]}
iex(10)> Expression.evaluate("Dear @IF(contact.gender = 'M', 'Sir', 'Client')", %{
...(10)> "contact" => %{
...(10)> "gender" => "O"
...(10)> }
...(10)> })
{:ok, ["Dear ", "Client"]}
The values of each chunk (either text or expression) is in the list returned by evaluate. The return values of Expressions are typed. The types are documented below under Types.
If you're looking for a shorthand to convert these to a single string output use Expression.evaluate_as_string!/3
.
iex(11)> Expression.evaluate_as_string!("Your next appointment is @(DATEVALUE(EDATE(contact.appointment, 1), \"%Y-%m-%d\"))", %{
...(11)> "contact" => %{
...(11)> "appointment" => "2020-12-13T23:35:55"
...(11)> }
...(11)> })
"Your next appointment is 2021-01-13"
See Engaged.Callbacks
for all the functions implemented.
Often, when one has an email address in an expression, one would want to leave it as is. Expressions accommodates this by having expressions that evaluate to nil left as is.
iex(3)> Expression.evaluate_as_string!("[email protected]")
"[email protected]"
A thing to note though is that if @support.com
does resolve to something with the given context,
it will still be applied:
iex(6)> Expression.evaluate_as_string!("[email protected]", %{
...(6)> "support" => %{
...(6)> "com" => "example placeholder value"
...(6)> }
...(6)> })
"infoexample placeholder value"
To properly escape the @
, prefix it with another @
as the example below:
iex(4)> Expression.evaluate_as_string!("info@@support.com")
"[email protected]"
Expression knows the following types:
iex> # Floats
iex> Expression.evaluate("@(1.23)")
{:ok, [1.23}
iex> # Integers
iex> Expression.evaluate("@(1)")
{:ok, [1]}
iex> # DateTime in ISO and a sloppy US formats
iex> Expression.evaluate("@(2020-12-13T23:35:55)")
{:ok, [~U[2020-12-13 23:35:55.0Z]]}
iex> Expression.evaluate("@(13-12-2020 23:35:55)")
{:ok, [~U[2020-12-13 23:35:55Z]]}
iex> # case insensitive booleans
iex> Expression.evaluate("@(true)")
{:ok, [true]}
iex> Expression.evaluate("@(TrUe)")
{:ok, [true]}
iex> Expression.evaluate("@(false)")
{:ok, [false]}
iex> Expression.evaluate("@(FaLsE)")
{:ok, [false]}
- It may be worth implementing a binary only expression parser, something
that is guaranteed to only return a
true
orfalse
. That could be useful when building decision trees with dynamic conditionals depending on context.
This is not available in Hex.pm or Hexdocs.pm yet
If available in Hex, the package can be installed
by adding expression
to your list of dependencies in mix.exs
:
def deps do
[
{:expression, "~> 2.38.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/expression.