SkillAgentSearch skills...

Tablex

An implementation of Decision Table in Elixir.

Install / Use

/learn @elixir-tablex/Tablex
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Tablex - Decision Tables in Elixir Code

Tablex is an implementation of the [Decision Table][] in Elixir. Its goal is to make maitaining domain rules easy.

Quick demo

Let's assume we decide what to do everyday based on day of week and the weather, as the following table indicates:

<table class="tablex horizontal"><colgroup> <col span="1" class="rule-number"> <col span="2" class="input"> <col span="1" class="output"> </colgroup> <thead><tr><th class="hit-policy hit-policy-F"></th><th class="input">day (string)</th><th class="input">weather (string)</th><th class="output">activity</th></tr></thead><tbody><tr><td class="rule-number">1</td><td rowspan="2" class="input">Monday, Tuesday, Wednesday, Thursday</td><td class="input">rainy</td><td class="output">read</td></tr><tr><td class="rule-number">2</td><td class="input">-</td><td class="output">read, walk</td></tr><tr><td class="rule-number">3</td><td rowspan="2" class="input">Friday</td><td class="input">sunny</td><td class="output">soccer</td></tr><tr><td class="rule-number">4</td><td class="input">-</td><td class="output">swim</td></tr><tr><td class="rule-number">5</td><td class="input">Saturday</td><td class="input">-</td><td class="output">watch movie, games</td></tr><tr><td class="rule-number">6</td><td class="input">Sunday</td><td class="input">-</td><td class="output">null</td></tr></tbody></table>

We can use a similar tabular form of the code in an Elixir program:

...> plans = Tablex.new("""
...> F   day (string)                         weather (string) || activity
...> 1   Monday,Tuesday,Wednesday,Thursday    rainy            || read
...> 2   Monday,Tuesday,Wednesday,Thursday    -                || read,walk
...> 3   Friday                               sunny            || soccer
...> 4   Friday                               -                || swim
...> 5   Saturday                             -                || "watch movie",games
...> 6   Sunday                               -                || null
...> """)
...> 
...> Tablex.decide(plans, day: "Monday")
%{activity: ["read", "walk"]}
...> 
...> Tablex.decide(plans, day: "Friday", weather: "sunny")
%{activity: "soccer"}
...> 
...> Tablex.decide(plans, day: "Sunday")
%{activity: nil}

The above code demonstrates how we can determine what to do based on a set of rules which are represented in a decision table on day and weather condition.

Inside the table, we defined the decision logic with:

  1. An indicator of hit policy, F in this case meaning the first rule matched will be applied. See Hit Policies section for more information.
  2. Two input stubs, day and weather which are both strings. See Input Stubs section
  3. An output stub, activity in this case. See Output Stubs section
  4. Six rules which take inputs and determine the activity output. See Rules section
  5. A friendly expression in each cell of the rules. See Expression section

Vertical Table

Vertical tables are the same as horizontal ones. It's just a matter of direction. The following tables are the same:

F product_category   competitor_pricing       product_features   || launch_decision   reasoning
1 Electronics        "Higher than Competitor" "More Features"    || Launch            "Competitive Advantage"
2 Electronics        "Lower than Competitor"  "Same Features"    || Launch            "Price Advantage"
3 Fashion            "Same as Competitor"     "New Features"     || "Do Not Launch"   "Lack of Differentiation"
<table class="tablex horizontal"><colgroup><col span="1" class="rule-number"><col span="3" class="input"><col span="2" class="output"></colgroup><thead><tr><th class="hit-policy hit-policy-F">F</th><th class="input">Product Category</th><th class="input">Competitor Pricing</th><th class="input">Product Features</th><th class="output">Launch Decision</th><th class="output">Reasoning</th></tr></thead><tbody><tr><td class="rule-number">1</td><td rowspan="2" class="input"><span class="tbx-exp-string">Electronics</span></td><td class="input"><span class="tbx-exp-string">Higher than Competitor</span></td><td class="input"><span class="tbx-exp-string">More Features</span></td><td class="output"><span class="tbx-exp-string">Launch</span></td><td class="output"><span class="tbx-exp-string">Competitive Advantage</span></td></tr><tr><td class="rule-number">2</td><td class="input"><span class="tbx-exp-string">Lower than Competitor</span></td><td class="input"><span class="tbx-exp-string">Same Features</span></td><td class="output"><span class="tbx-exp-string">Launch</span></td><td class="output"><span class="tbx-exp-string">Price Advantage</span></td></tr><tr><td class="rule-number">3</td><td class="input"><span class="tbx-exp-string">Fashion</span></td><td class="input"><span class="tbx-exp-string">Same as Competitor</span></td><td class="input"><span class="tbx-exp-string">New Features</span></td><td class="output"><span class="tbx-exp-string">Do Not Launch</span></td><td class="output"><span class="tbx-exp-string">Lack of Differentiation</span></td></tr></tbody></table>
====
F                    || 1                        2                       3
product_category     || Electronics              Electronics             Fashion
competitor_pricing   || "Higher than Competitor" "Lower than Competitor" "Same as Competitor"
product_features     || "More Features"          "Same Features"         "New Features"
====
launch_decision      || Launch                   Launch                  "Do Not Launch"
reasoning            || "Competitive Advantage"  "Price Advantage"       "Lack of Differentiation"
<table class="tablex vertical"><tbody><tr><th class="hit-policy hit-policy-F">F</th><th class="rule-number">1</th><th class="rule-number">2</th><th class="rule-number">3</th></tr></tbody><tbody><tr><th class="input">Product Category</th><td colspan="2"><span class="tbx-exp-string">Electronics</span></td><td><span class="tbx-exp-string">Fashion</span></td></tr><tr><th class="input">Competitor Pricing</th><td><span class="tbx-exp-string">Higher than Competitor</span></td><td><span class="tbx-exp-string">Lower than Competitor</span></td><td><span class="tbx-exp-string">Same as Competitor</span></td></tr><tr><th class="input">Product Features</th><td><span class="tbx-exp-string">More Features</span></td><td><span class="tbx-exp-string">Same Features</span></td><td><span class="tbx-exp-string">New Features</span></td></tr></tbody><tfoot><tr><th class="output">Launch Decision</th><td><span class="tbx-exp-string">Launch</span></td><td><span class="tbx-exp-string">Launch</span></td><td><span class="tbx-exp-string">Do Not Launch</span></td></tr><tr><th class="output">Reasoning</th><td><span class="tbx-exp-string">Competitive Advantage</span></td><td><span class="tbx-exp-string">Price Advantage</span></td><td><span class="tbx-exp-string">Lack of Differentiation</span></td></tr></tfoot></table> ## Input Stubs

Inputs can be defined with a set of name (type[, description]) pairs. For example:

  • Age (integer) defines an input field whose name is "age" and type is integer.
  • DOB (date, date of birth) defines a date input field with a description label.

Name

Names can contain spaces in them if they are quoted. The following names are valid:

  • year_month_day
  • yearMonthDay
  • "year month day"

They will all be converted to year_month_day.

Type

Currently the following types are supported:

  • integer
  • float
  • number
  • string
  • bool

When types are specified, the input value shall be of the same type as specified.

Output Stubs

Output stubs are defined as name (type[, description]) where

  • name can be a string which will be converted to an underscored atom;
  • type can be either of the supported types (the same as inputs, see above section);
  • description is optional and is currently ignored.

Rules

After output stub definitions, each of the following rows defines a rule entry, with the format:

rule_number input_exp_1 input_exp_2 ... input_exp_m || output_exp_1 output_exp_2 ... output_exp_n

Rule number is primarily used for ordering. The rule with the lowest rule number has the highest priority. Input expressions and output expressions are separated by "||".

Expression

Currently only these types are supported:

  • literal numeric value: integer and float (without scientific notation)
  • literal quoted string in "
  • boolean
  • comparison: >, >=, <, <=
  • range, e.g. 5..10
  • nil ("null")
  • list of numeric, string, range, bool, nil or comparison; can be mixed
  • any ("-")

The following types of expressions are planned:

  • date
  • time
  • datetime
  • function

Hit policies

There are several hit policies to indicate how matched rules are applied.

  • F (First matched) - the first matched rule will be applied.
  • C (Collect) - all matched rules will be collected into result list.
  • M (Merge) - all matched rules will be reduced (merged) into a single return entry, until there's no - in the output.
  • R (Reverse Merge) - similar to merge but in a reversed order.

Examples:

First Hit

iex> table = Tablex.new("""
...> F   age (integer)  || f (float)
...> 1   > 60           || 3.0
...> 2   50..60         || 2.5
...> 3   31..49         || 2.0
...> 4   15..18,20..30  || 1.0
...> 5   -              || 0
...> """
...> )
...> 
...> Tablex.decide(table, age: 30)
%{f: 1.0}
iex> Tablex.decide(table, age: 55)
%{f: 2.5}
iex> Tablex.decide(table, age: 22)
%{f: 1.0}
iex> Tablex.decide(table, age: 17)
%{f: 1.0}
iex> Tablex.decide(table, age: 1)
%{f: 0}
iex> table = Tablex.new("""
...> F   age (integer)  years_of_service    || holidays (integer)
...> 1   >=60           -                   || 3
...> 2   45..59         <30                 || 2
...> 3   -              >=30                || 22
...> 4   <18            -                   || 5
...

Related Skills

View on GitHub
GitHub Stars54
CategoryDevelopment
Updated2mo ago
Forks6

Languages

Elixir

Security Score

80/100

Audited on Jan 12, 2026

No findings