README.md in csv_decision-0.0.1 vs README.md in csv_decision-0.0.2
- old
+ new
@@ -1,20 +1,134 @@
-# csv_decision - Work In Progress
-`csv_decision` is a Ruby gem for CSV based decision tables. It accepts decision table logic encoded in
-a CSV file, which can then be used to implement complex conditional logic.
+CSV Decision
+============
-`csv_decision` has many useful features:
- * able to parse and load into memory many CSV files for subsequent processing
- * can return the first matching row as a hash, or accumulate all matches as an array of hashes
- * input columns may be indexed for fast lookup performance
- * can use regular expressions, Ruby-style ranges and function calls to implement complex decision logic
- * all CSV cells are parsed for correctness, and friendly error messages generated for bad input
- * can be safely extended with user defined Ruby functions for tailored logic
- * good decision time performance
- * flexible options for tailoring behavior and defaults
+<a href="https://codeclimate.com/github/bpvickers/csv_decision/maintainability"><img src="https://api.codeclimate.com/v1/badges/466a6c52e8f6a3840967/maintainability" /></a>
+[![Build Status](https://travis-ci.org/bpvickers/csv_decision.svg?branch=master)](https://travis-ci.org/bpvickers/csv_decision)
+[![Coverage Status](https://coveralls.io/repos/github/bpvickers/csv_decision/badge.svg?branch=master)](https://coveralls.io/github/bpvickers/csv_decision?branch=master)
+[![Gem Version](https://badge.fury.io/rb/csv_decision.svg)](http://badge.fury.io/rb/csv_decision)
+
+# CSV based Ruby decision tables
+
+`csv_decision` is a Ruby gem for CSV (comma separated values) based
+[decision tables](https://en.wikipedia.org/wiki/Decision_table).
+It accepts decision tables written in a CSV file, which can then be used to execute
+complex conditional logic against an input hash, producing a decision as an output hash.
+
+ ### `csv_decision` features
+ * fast decision-time performance
+ * can use regular expressions, numeric comparisons and Ruby-style ranges
+ * accepts data as a file, CSV string or an array of arrays.
+ * all CSV cells are parsed for correctness, and helpful error messages generated for bad
+ inputs
- ### Why use CSV Decision?
+ ### Planned features
+ * input columns may be indexed for faster lookup performance
+ * either returns the first matching row as a hash, or accumulates all matches as an
+ array of hashes.
+ * use of output functions to formulate the final decision
+ * can use column symbol references or built-in guard functions for matching
+ * may be extended with user-defined Ruby functions for tailored logic
+ * can use if conditions to filter the results of multi-row decision output
- Typical "business logic" is notoriously illogical -- full of corner cases and irregular exceptions.
- A decision table can capture data-based decisions in a way that comes naturally to analysts and subject matter
- experts, who typically use spreadsheet models. Business logic can be encapsulated, avoiding the need to write
- tortuous conditional expressions in Ruby that draws the ire of `rubocop` and its ilk.
+ ### Why use `csv_decision`?
+
+ Typical "business logic" is notoriously illogical -- full of corner cases and one-off
+ exceptions.
+ A decision table can capture data-based decisions in a way that comes more naturally
+ to subject matter experts, who typically prefer spreadsheet models.
+ Business logic may then be encapsulated, avoiding the need to write tortuous
+ conditional expressions in Ruby that draw the ire of `rubocop` and its ilk.
+
+ This gem takes its inspiration from
+ [rufus/decision](https://github.com/jmettraux/rufus-decision).
+ (That gem is no longer maintained and has issues with execution performance.)
+
+ ### Installation
+
+ To get started, just add `csv_decision` to your `Gemfile`, and then run `bundle`:
+
+ ```ruby
+ gem 'csv_decision', '~> 0.0.1'
+ ```
+
+ ### Simple example
+
+ A decision table may be as simple or as complex as you like (although very complex
+ tables defeat the whole purpose).
+ Basic usage will be illustrated by an example taken from:
+ https://jmettraux.wordpress.com/2009/04/25/rufus-decision-11-ruby-decision-tables/.
+
+ This example considers two input conditions: `topic` and `region`.
+ These are labeled `in`. Certain combinations yield an output value for `team_member`,
+ labeled `out`.
+
+```
+in :topic | in :region | out :team_member
+----------+-------------+-----------------
+sports | Europe | Alice
+sports | | Bob
+finance | America | Charlie
+finance | Europe | Donald
+finance | | Ernest
+politics | Asia | Fujio
+politics | America | Gilbert
+politics | | Henry
+ | | Zach
+```
+
+ When the topic is `finance` and the region is `Europe` the team member `Donald`
+ is selected.
+
+ This is a "first match" decision table in that as soon as a match is made execution
+ stops and a single output value (hash) is returned.
+
+ The ordering of rows matters. `Ernest`, who is in charge of `finance` for the rest of
+ the world, except for `America` and `Europe`, *must* come after his colleagues
+ `Charlie` and `Donald`. `Zach` has been placed last, catching all the input combos
+ not matching any other row.
+
+ Now for some code.
+
+ ```ruby
+ data = <<~DATA
+ in :topic, in :region, out :team_member
+ sports, Europe, Alice
+ sports, , Bob
+ finance, America, Charlie
+ finance, Europe, Donald
+ finance, , Ernest
+ politics, Asia, Fujio
+ politics, America, Gilbert
+ politics, , Henry
+ , , Zach
+ DATA
+
+ table = CSVDecision.parse(data)
+
+ table.decide(topic: 'finance', region: 'Europe') # returns team_member: 'Donald'
+ table.decide(topic: 'sports', region: nil) # returns team_member: 'Bob'
+ table.decide(topic: 'culture', region: 'America') # team_member: 'Zach'
+```
+
+ An empty `in` cell means "matches any value".
+
+ If you have cloned this gem's git repo, then this example can also be run by loading
+ the table from a CSV file:
+
+ ```ruby
+table = CSVDecision.parse(Pathname('spec/data/valid/simple_example.csv'))
+```
+
+ For more examples see `spec/csv_decision/table_spec.rb`.
+ Complete documentation of all table parameters is in the code - see
+ `lib/csv_decision/parse.rb` and `lib/csv_decision/table.rb`.
+
+
+ ### Testing
+
+ `csv_decision` includes thorough [RSpec](http://rspec.info) tests:
+
+ ```bash
+ # Execute within a clone of the csv_decision Git repository:
+ bundle install
+ rspec
+ ```