diff --git a/.clj-kondo/rewrite-clj/rewrite-clj/config.edn b/.clj-kondo/rewrite-clj/rewrite-clj/config.edn
new file mode 100644
index 0000000..19ecae9
--- /dev/null
+++ b/.clj-kondo/rewrite-clj/rewrite-clj/config.edn
@@ -0,0 +1,5 @@
+{:lint-as
+ {rewrite-clj.zip/subedit-> clojure.core/->
+ rewrite-clj.zip/subedit->> clojure.core/->>
+ rewrite-clj.zip/edit-> clojure.core/->
+ rewrite-clj.zip/edit->> clojure.core/->>}}
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
index b36b14b..b63cbf7 100644
--- a/.github/workflows/format.yml
+++ b/.github/workflows/format.yml
@@ -13,6 +13,19 @@ jobs:
ref: ${{ github.head_ref }}
token: ${{ secrets.WALL_BREW_BOT_PAT }}
+ - name: Cache maven dependencies
+ uses: actions/cache@v3
+ env:
+ cache-name: cache-maven
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-clj-${{ hashFiles('**/project.clj') }}
+ restore-keys: |
+ ${{ runner.os }}-clj
+
+ - name: Install Clojure dependencies
+ run: lein deps
+
- name: Install cljstyle
uses: just-sultanov/setup-cljstyle@v1
with:
@@ -22,6 +35,10 @@ jobs:
run: |
cljstyle fix --report --report-timing --verbose
+ - name: Render Changelog
+ run: |
+ lein sealog render
+
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5.0.0
with:
diff --git a/.sealog/changes/2-0-0.edn b/.sealog/changes/2-0-0.edn
index e3b6039..d1f55b5 100644
--- a/.sealog/changes/2-0-0.edn
+++ b/.sealog/changes/2-0-0.edn
@@ -13,7 +13,7 @@
"Display functions for all unit types."]
:changed ["Internal functions that convert between unit systems now use `brewtility.units`"]
:deprecated []
- :removed ["`brewility.color` has been removed in favor of `brewtility.units.color`"
+ :removed ["`brewtility.color` has been removed in favor of `brewtility.units.color`"
"`brewtility.units/convert-weight` has been removed in favor of `brewtility.units/convert` and `brewtility.units.weight/convert`"
"`brewtility.units/convert-volume` has been removed in favor of `brewtility.units/convert` and `brewtility.units.volume/convert`"
"`brewtility.units/convert-temperature` has been removed in favor of `brewtility.units/convert` and `brewtility.units.temperature/convert`"]
diff --git a/.sealog/changes/2-1-0.edn b/.sealog/changes/2-1-0.edn
new file mode 100644
index 0000000..4fd519c
--- /dev/null
+++ b/.sealog/changes/2-1-0.edn
@@ -0,0 +1,16 @@
+{:version {:major 2
+ :minor 1
+ :patch 0}
+ :version-type :semver3
+ :changes {:added ["`brewtility.units.alcohol-content` for converting and displaying alcohol content."
+ "`brewtility.units.bitterness` for rendering displayable IBU values."
+ "`brewtility.units.carbonation` for rendering displayable carbonation values."
+ "`brewtility.units.specific-gravity` now supports measurements in degrees plato."
+ "`brewtility.predicates.options` for option map keys shared across predicate namespaces."]
+ :changed ["Functions in `brewtility.calculations` will throw targeted exceptions for invalid values instead of relying on the underlying Math implementation to do so."
+ "Functions in `brewtility.precision` will throw targeted exceptions for invalid values instead of relying on the underlying Math implementation to do so."
+ "`brewtility.units` now supports a `:precision` option map key for all conversion functions. This key will round the converted value to the specified number of decimal places. Defaults to the precision of the converted value."
+ "`brewtility.units.color` now supports a reverse-lookup for known RGBa values."
+ "All functions in `brewtility.predicates` now support an option map as a second argument to make their arities consistent."]
+ :removed ["`^:const` metadata has been removed from conversion maps"]}
+ :timestamp "2024-03-11T18:47:13.522931300Z"}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 49ac9e7..f33d632 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## Table of Contents
+* [2.1.0 - 2024-03-11](#210---2024-03-11)
* [2.0.1 - 2024-03-11](#201---2024-03-11)
* [2.0.0 - 2023-06-11](#200---2023-06-11)
* [1.5.0 - 2023-02-13](#150---2023-02-13)
@@ -15,6 +16,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* [1.1.0 - 2020-08-15](#110---2020-08-15)
* [1.0.0 - 2020-07-19](#100---2020-07-19)
+## 2.1.0 - 2024-03-11
+
+* Added
+ * `brewtility.units.alcohol-content` for converting and displaying alcohol content.
+ * `brewtility.units.bitterness` for rendering displayable IBU values.
+ * `brewtility.units.carbonation` for rendering displayable carbonation values.
+ * `brewtility.units.specific-gravity` now supports measurements in degrees plato.
+ * `brewtility.predicates.options` for option map keys shared across predicate namespaces.
+* Changed
+ * Functions in `brewtility.calculations` will throw targeted exceptions for invalid values instead of relying on the underlying Math implementation to do so.
+ * Functions in `brewtility.precision` will throw targeted exceptions for invalid values instead of relying on the underlying Math implementation to do so.
+ * `brewtility.units` now supports a `:precision` option map key for all conversion functions. This key will round the converted value to the specified number of decimal places. Defaults to the precision of the converted value.
+ * `brewtility.units.color` now supports a reverse-lookup for known RGBa values.
+ * All functions in `brewtility.predicates` now support an option map as a second argument to make their arities consistent.
+* Removed
+ * `^:const` metadata has been removed from conversion maps
+
## 2.0.1 - 2024-03-11
* Security
@@ -35,7 +53,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* Changed
* Internal functions that convert between unit systems now use `brewtility.units`
* Removed
- * `brewility.color` has been removed in favor of `brewtility.units.color`
+ * `brewtility.color` has been removed in favor of `brewtility.units.color`
* `brewtility.units/convert-weight` has been removed in favor of `brewtility.units/convert` and `brewtility.units.weight/convert`
* `brewtility.units/convert-volume` has been removed in favor of `brewtility.units/convert` and `brewtility.units.volume/convert`
* `brewtility.units/convert-temperature` has been removed in favor of `brewtility.units/convert` and `brewtility.units.temperature/convert`
diff --git a/Makefile b/Makefile
index 4b1a5d7..a91d4fd 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@ version/major:
@ lein change version leiningen.release/bump-version release
@ lein sealog bump major
@ lein pom
+ @ npm version major --no-git-tag-version
version/minor:
$(info Updating minor version and adding CHANGELOG entry...)
@@ -22,6 +23,7 @@ version/minor:
@ lein change version leiningen.release/bump-version release
@ lein sealog bump minor
@ lein pom
+ @ npm version minor --no-git-tag-version
version/patch:
$(info Updating patch version and adding CHANGELOG entry...)
@@ -30,6 +32,7 @@ version/patch:
@ lein change version leiningen.release/bump-version release
@ lein sealog bump patch
@ lein pom
+ @ npm version patch --no-git-tag-version
changelog/render:
$(info Rendering CHANGELOG...)
diff --git a/README.md b/README.md
index d93f3ba..fbf4fe9 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@
[![Clojars Project](https://img.shields.io/clojars/v/com.wallbrew/brewtility.svg)](https://clojars.org/com.wallbrew/brewtility)
![Clojure and ClojureScript CI](https://github.com/Wall-Brew-Co/brewtility/workflows/Clojure%20and%20ClojureScript%20CI/badge.svg)
[![cljdoc badge](https://cljdoc.org/badge/com.wallbrew/brewtility)](https://cljdoc.org/d/com.wallbrew/brewtility/CURRENT)
+[![GitHub](https://img.shields.io/github/license/Wall-Brew-Co/brewtility)](https://github.com/Wall-Brew-Co/brewtility/blob/master/LICENSE)
+[![Twitter Follow](https://img.shields.io/twitter/follow/WallBrew?style=social)](https://twitter.com/WallBrew)
A Clojure(Script) utility library for all of your brewing needs.
@@ -62,6 +64,10 @@ lein test-build
The tests will also execute on the JVM, to ensure the library is compatible for apps in both deployment environments.
+## Contributors
+
+
+
## License
Copyright © 2020-2023 - [Wall Brew Co](https://wallbrew.com/)
diff --git a/doc/api/units.md b/doc/api/units.md
index a6a3e05..762a4b9 100644
--- a/doc/api/units.md
+++ b/doc/api/units.md
@@ -30,6 +30,10 @@ This provides a consistent interface to every system of measure, unit type, and
(units/convert units/volume 20 :teaspoon :liter)
;; => 0.099
+;; You can also round the conversion to a specified precision
+(units/convert units/volume 20 :teaspoon :liter {:precision 1})
+;; => 0.1
+
;; If you only plan on dealing with volumes,
;; then you can import the `brewtility.units.volume` namespace
(volume/convert 9.99209 :imperial-pint :american-pint)
@@ -72,6 +76,8 @@ Brewtility supports four systems of measure:
These are the most commonly seen systems in brewing.
There are measurement functions for the most common types of measurements within these systems:
+- [Bitterness](##bitterness)
+- [Carbonation](##carbonation)
- [Color](##color)
- [Pressure](##pressure)
- [Specific Gravity](##specific-gravity)
@@ -80,6 +86,22 @@ There are measurement functions for the most common types of measurements within
- [Volume](##volume)
- [Weight](##weight)
+### Bitterness
+
+Currently, brewtility supports the following bitterness measurements:
+
+- [IBU](https://en.wikipedia.org/wiki/International_bitterness_units)
+
+While there is currently only one system, the same namespace and functionality exists as the other measurement types.
+This allows for progressive evolution, and provides a consistent interface to every measurement type encoded in the BeerXML specification.
+
+### Carbonation
+
+Currently, brewtility supports the following carbonation measurements:
+
+- [Volumes of CO2](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages)
+- [Grams per Liter](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages)
+
### Color
Currently, brewtility supports the following types of color:
@@ -89,10 +111,6 @@ Currently, brewtility supports the following types of color:
- [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour)
- [RGBa](https://en.wikipedia.org/wiki/RGBA_color_model)
-The `RGBa` system is special, as it can only be used as an argument for the result of a unit conversion.
-Unfortunately, there is not a great deterministic way to cast the values back to the other systems.
-brewtility will thrown an exception in this case and explain the problem.
-
### Pressure
Currently, brewtility supports the following types of pressure:
@@ -156,7 +174,7 @@ Currently, brewtility supports the following types of volume:
- [tablespoon](https://en.wikipedia.org/wiki/Tablespoon)
- [teaspoon](https://en.wikipedia.org/wiki/Teaspoon))
-Given the prevalence of the French spellings in English recipes, both `:litre` and `:liter` can be passed as options.
+Given the prevalence of the non-US spellings in English recipes, both `:litre` and `:liter` can be passed as options.
### Weight
diff --git a/doc/cljdoc.edn b/doc/cljdoc.edn
index f363c4b..9c18375 100644
--- a/doc/cljdoc.edn
+++ b/doc/cljdoc.edn
@@ -3,13 +3,14 @@
["Community" {}
["Contributing" {:file "CONTRIBUTING.md"}]
["Code of Conduct" {:file "CODE_OF_CONDUCT.md"}]
+ ["License" {:file "LICENSE.md"}]
["Security Policy" {:file "SECURITY.md"}]]
["Functionality" {}
["Calculations" {:file "doc/api/calculations.md"}]
- ["Color" {:file "doc/api/color.md"}]
["Precision" {:file "doc/api/precision.md"}]
["Predicates" {:file "doc/api/predicates.md"}]
["Units of Measure" {:file "doc/api/units.md"}]
["Wrapping" {:file "doc/api/wrapping.md"}]]
["Adopted Patterns" {}
+ ["Enricher Pattern" {:file "doc/patterns/enricher-pattern.md"}]
["Symbolic Keywords" {:file "doc/patterns/symbolic_keywords.md"}]]]}
diff --git a/doc/patterns/enricher-pattern.md b/doc/patterns/enricher-pattern.md
new file mode 100644
index 0000000..463b526
--- /dev/null
+++ b/doc/patterns/enricher-pattern.md
@@ -0,0 +1,134 @@
+# Enricher Pattern
+
+In [BeerXML](http://www.beerxml.com/ "The XML standard to encode beer data"), and, by extension, [common-beer-format](https://github.com/Wall-Brew-Co/common-beer-format "A clojure library/spec for BeerXML"), there are specifications which ultimately represent and encode the same concept.
+For a concrete example, consider a sample [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc "The specification for a piece of brewing equipment") record.
+
+```clj
+{:name "8 Gal pot with 5 gal Igloo Cooler"
+ :boil-size 22.71
+ :trub-chiller-loss 0.95
+ :boil-time 60.0
+ :version 1
+ :tun-specific-heat 0.3
+ :batch-size 18.93
+ :display-boil-size "6.0 US Gallons"}
+```
+
+In the above, you can find two representations of the pre-boil volume that piece of equipment held.
+By the standard, the `:boil-size` is standardized to be the volume in litres, and the `:display-boil-size` is meant to represent that value in a region and human friendly way.
+This is great for users; however, it can be unwieldy in applications for a few to store and transmit data which may only be used in the display layer.
+Programmatically, we are often more interested in a smaller subset of the equipment record and will defer computing display values until they are needed.
+
+While the unit conversion is simple, it can often lead to front-end code like this:
+
+```clj
+(defn display-equipment
+ [equipment system-of-measure]
+ [:span
+ [:h1 (:name equipment)]
+ [:ul
+ [:li (str "Boil volume: " (->display (convert-units (:boil-size equipment) system-of-measure)))]
+ (when (:tun-weight equipment)
+ [:li (str "Mash Tun Weight: " (->display (convert-units (:tun-weight equipment) system-of-measure)))])
+ ...
+ ]])
+```
+
+Helper functions may be extracted, but the above code would certainly benefit from the `:display-boil-size` and `:display-tun-weight` fields which may optionally exist on the `equipment` record.
+As a utility library for beer data, brewtility comes with the functionality needed to compute these display fields; however, keeping them as loose datums isn't fully desirable either.
+In the contexts we want display data available for an equipment record, it's much easier to provide that data with the equipment record.
+To that end, this library implements an enrichment pattern.
+
+## Enrichers
+
+An enrichment function is a function from maps to maps, which non-destructively adds to the source value derived information.
+For example, if we know the user's location, we could infer wether Metric or Imperial measurements would be more appropriate to display.
+With that information, we could leverage an enricher to modify the prior equipment example:
+
+```clj
+(def igloo-cooler
+ {:name "8 Gal pot with 5 gal Igloo Cooler"
+ :boil-size 22.71
+ :trub-chiller-loss 0.95
+ :boil-time 60.0
+ :version 1
+ :tun-specific-heat 0.3
+ :batch-size 18.93})
+
+(require '[brewtility.enrich.equipment :as enrich])
+
+(enrich/enrich-display-boil-size igloo-cooler {:system-of-measure :imperial})
+;; => {:name "8 Gal pot with 5 gal Igloo Cooler"
+;; :boil-size 22.71
+;; :trub-chiller-loss 0.95
+;; :boil-time 60.0
+;; :version 1
+;; :tun-specific-heat 0.3
+;; :batch-size 18.93
+;; :display-boil-size "6.0 US Gallons"}
+;;
+```
+
+If we wanted to calculate multiple display values in serial, we can also perform a best-effort enrichment of the entire record.
+
+```clj
+(enrich/enrich-equipment igloo-cooler {:system-of-measure :imperial})
+;; => {:name "8 Gal pot with 5 gal Igloo Cooler"
+;; :boil-size 22.71
+;; :trub-chiller-loss 0.95
+;; :boil-time 60.0
+;; :version 1
+;; :tun-specific-heat 0.3
+;; :batch-size 18.93
+;; :display-boil-size "6.0 US Gallons"
+;; :display-trub-chiller-loss "0.251 US Gallons"
+;; :display-batch-size "5.0 US Gallons"}
+;;
+```
+
+Or, in our example front-end:
+
+```clj
+(defn fetch-equipment!
+ [equipment-id]
+ (-> (http/get (str some-url "/equipment/" equipment-id))
+ :body
+ json/decode
+ enrich/enrich-equipment {:system-of-measure :imperial})))
+
+(defn display-equipment
+ [equipment]
+ [:span
+ [:h1 (:name equipment)]
+ [:ul
+ [:li (str "Boil volume: " (:display-boil-size equipment))))]
+ (when (:display-tun-weight equipment)
+ [:li (str "Mash Tun Weight: " (display-tun-weight equipment))])
+ ...
+ ]])
+
+(defn fetch-and-display-equipment!
+ [equipment-id]
+ (-> equipment-id fetch-equipment! display-equipment))
+```
+
+In the above, we're able to calculate display values for the boil size, batch size, and trub chiller loss since the data sources for that information.
+While the equipment record does specify display values for the tun's volume, the source of that data is missing- and therefore excluded.
+
+## Implementations
+
+Enricher functions exist for each of the core specifications supported by BeerXML and common-beer-format.
+
+- [Equipment](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/equipment.cljc "Equipment enrichers")
+- [Fermentables](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/fermentables.cljc "Fermentable enrichers")
+- [Hops](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/hops.cljc "Hop enrichers")
+- [Mash](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/mash.cljc "Mash enrichers")
+- [Miscs](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/miscs.cljc "Misc enrichers")
+- [Recipes](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/recipes.cljc "Recipe enrichers")
+- [Styles](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/styles.cljc "Style enrichers")
+- [Waters](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/waters.cljc "Water enrichers")
+- [yeasts](https://github.com/Wall-Brew-Co/brewtility/blob/master/src/brewtility/enrich/yeasts.cljc "Yeast enrichers")
+
+## Inspiration
+
+- [Maybe Not - Rich Hickey](https://www.youtube.com/watch?v=YR5WdGrpoug&ab_channel=ClojureTV "A great presentation on the types of problems type systems try to solve")
diff --git a/package-lock.json b/package-lock.json
index 28aa715..79ff4e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "brewtility",
- "version": "2.0.1",
+ "version": "2.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "brewtility",
- "version": "2.0.1",
+ "version": "2.1.0",
"license": "MIT",
"devDependencies": {
"karma": "^6.3.16",
@@ -605,20 +605,6 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
diff --git a/package.json b/package.json
index 3a45f00..ba98fc5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "brewtility",
- "version": "2.0.1",
+ "version": "2.1.0",
"description": "Utility functions for all of your brewing needs.",
"main": "index.js",
"directories": {
diff --git a/pom.xml b/pom.xml
index e64abb7..81b5a8b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.wallbrew
brewtility
jar
- 2.0.1
+ 2.1.0
brewtility
Utility functions for all of your brewing needs.
https://github.com/Wall-Brew-Co/brewtility
@@ -20,7 +20,7 @@
https://github.com/Wall-Brew-Co/brewtility
scm:git:git://github.com/Wall-Brew-Co/brewtility.git
scm:git:ssh://git@github.com/Wall-Brew-Co/brewtility.git
- 0c12a150d6a7e185d1d1887bc8580aecf44dadf6
+ 56bd49d1a2e7addf14615c5d5bb4b096f9cf8e3c
src
@@ -81,6 +81,12 @@
1.11.132
provided
+
+ cider
+ cider-nrepl
+ 0.31.0
+ test
+
com.wallbrew
common-beer-data
@@ -99,6 +105,12 @@
0.1.11
test
+
+ nrepl
+ nrepl
+ 1.0.0
+ test
+
diff --git a/project.clj b/project.clj
index 952594d..476754e 100644
--- a/project.clj
+++ b/project.clj
@@ -1,4 +1,4 @@
-(defproject com.wallbrew/brewtility "2.0.1"
+(defproject com.wallbrew/brewtility "2.1.0"
:description "Utility functions for all of your brewing needs."
:url "https://github.com/Wall-Brew-Co/brewtility"
:license {:name "MIT"
@@ -25,10 +25,12 @@
:deploy-branches ["master"]
:profiles {:uberjar {:aot :all}
- :dev {:dependencies [[com.wallbrew/common-beer-data "1.3.0"]
+ :dev {:dependencies [[cider/cider-nrepl "0.31.0"]
+ [com.wallbrew/common-beer-data "1.3.0"]
[com.wallbrew/common-beer-format "2.2.1"]
- [doo "0.1.11"]]
- :plugins [[lein-doo "0.1.11"]]}}
+ [doo/doo "0.1.11"]
+ [nrepl/nrepl "1.0.0"]]
+ :plugins [[lein-doo/lein-doo "0.1.11"]]}}
:aliases {"test-build" ["do" "clean" ["cljsbuild" "once" "test"] ["doo" "once"] ["test"]]}
diff --git a/src/brewtility/calculations.cljc b/src/brewtility/calculations.cljc
index 14e1259..783ecc3 100644
--- a/src/brewtility/calculations.cljc
+++ b/src/brewtility/calculations.cljc
@@ -7,18 +7,27 @@
[brewtility.units.options :as options]
[brewtility.units.time :as time]
[brewtility.units.volume :as volume]
- [brewtility.units.weight :as weight]))
+ [brewtility.units.weight :as weight])
+ (:refer-clojure :exclude [time]))
(defn normalize-fermentable
- "Given a `common-beer-format` conforming `fermentable`, normalize it for color computation."
+ "Given a `common-beer-format` conforming `fermentable`, normalize it for color computation.
+ If insufficient data is provided, this function will throw an exception."
{:added "1.0"}
- [fermentable]
- (let [is-not-grain? (not (fermentables/grain? fermentable))
- kg->lbs (fn [w] (weight/convert w options/kilogram options/pound))] ; MCU is calculated against pounds
- (cond-> fermentable
- true (update :amount kg->lbs)
- is-not-grain? (update :color #(color/convert % options/srm options/lovibond))))) ; Grain color is in Lovibond, all other fermentables use SRM
+ [{:keys [amount color] :as fermentable}]
+ (if (and (number? amount)
+ (number? color))
+ (let [is-not-grain? (not (fermentables/grain? fermentable))
+ ;; MCU is calculated against pounds
+ kg->lbs (fn [w] (weight/convert w options/kilogram options/pound))]
+ (cond-> fermentable
+ true (update :amount kg->lbs)
+ ;; Grain color is in Lovibond, all other fermentables use SRM
+ is-not-grain? (update :color #(color/convert % options/srm options/lovibond))))
+ (throw (ex-info "Cannot calculate color with non-numeric values" {:amount amount
+ :color color}))))
+
(defn calculate-malt-color-units
"Given a collection of `common-beer-format` conforming `fermentables`, and a conformed `batch-size` in liters, return the overall Malt Color Units for a recipe."
@@ -85,11 +94,15 @@
{:added "1.0"
:see-also ["gravity-points->potential-gravity"]}
[potential-gravity weight]
- (let [weight-in-pounds (weight/convert weight options/kilogram options/pound)]
- (-> potential-gravity
- (* 1000)
- (- 1000)
- (* weight-in-pounds))))
+ (if (and (number? potential-gravity)
+ (number? weight))
+ (let [weight-in-pounds (weight/convert weight options/kilogram options/pound)]
+ (-> potential-gravity
+ (* 1000)
+ (- 1000)
+ (* weight-in-pounds)))
+ (throw (ex-info "Cannot calculate gravity points with non-numeric values" {:potential-gravity potential-gravity
+ :weight weight}))))
(defn gravity-points->potential-gravity
@@ -97,11 +110,15 @@
{:added "1.0"
:see-also ["potential-gravity->gravity-points"]}
[gravity-points volume]
- (let [volume-in-gallons (volume/convert volume options/litre options/american-gallon)]
- (-> gravity-points
- (/ volume-in-gallons)
- (+ 1000)
- (/ 1000.0))))
+ (if (and (number? gravity-points)
+ (number? volume))
+ (let [volume-in-gallons (volume/convert volume options/litre options/american-gallon)]
+ (-> gravity-points
+ (/ volume-in-gallons)
+ (+ 1000)
+ (/ 1000.0)))
+ (throw (ex-info "Cannot calculate potential gravity with non-numeric values" {:gravity-points gravity-points
+ :volume volume}))))
(defn calculate-potential-gravity
@@ -117,7 +134,7 @@
(def gravity->abv-multiplier
- "The multiplier used to convert gravity to ABV.
+ "The multiplier used to convert gravity to ABV.
This is a constant, and is not configurable."
0.00135)
@@ -138,10 +155,10 @@
(calculate-potential-final-gravity fermentables batch-size default-attenuation))
([fermentables batch-size attenuation]
- (let [gravity (calculate-potential-gravity fermentables batch-size)
- gravity-points (-> gravity
- (* 1000)
- (- 1000))
+ (let [gravity (calculate-potential-gravity fermentables batch-size)
+ gravity-points (-> gravity
+ (* 1000)
+ (- 1000))
attenuated-points (* gravity-points attenuation)]
(-> gravity-points
@@ -152,7 +169,8 @@
(defn calculate-potential-abv
"Given a collection of `common-beer-format` conforming `fermentables`, and a conformed `batch-size` in liters, estimate the ABV.
- The primary fermentation yeast's `attenuation` may also be passed, otherwise 75% is assumed."
+ The primary fermentation yeast's `attenuation` may also be passed, otherwise 75% is assumed.
+ If insufficient data is provided, this function will throw an exception."
{:added "1.0"}
([fermentables batch-size]
(calculate-potential-abv fermentables batch-size default-attenuation))
@@ -169,6 +187,7 @@
(defn calculate-hop-utilization
"Calculate the percentage of alpha acid that a hop could release over `boil-duration` in a wort at a specific `gravity`.
Based on: http://howtobrew.com/book/section-1/hops/hop-bittering-calculations"
+ {:added "1.0"}
[gravity boil-duration]
(let [gravity-factor (* 1.65 (Math/pow 0.000125 (- gravity 1)))
time-factor (/ (- 1 (Math/pow Math/E (* -0.04 boil-duration))) 4.15)]
@@ -179,7 +198,7 @@
"Calculate the maximum amount of alpha acid released by `weight` ounce of a hop at `percent` alpha acid."
{:added "1.0"}
[weight alpha]
- (let [weight-in-ounces (weight/convert weight options/kilogram options/ounce)
+ (let [weight-in-ounces (weight/convert weight options/kilogram options/ounce)
aau-normalization-factor 100]
(* aau-normalization-factor weight-in-ounces alpha)))
@@ -187,16 +206,27 @@
(defn calculate-ibu-per-hop
"Given a `common-beer-format` conforming `hop`, `batch-size`, and `potential-gravity`, calculate the amount of IBUs generated."
{:added "1.0"}
- [hop batch-size potential-gravity]
- (let [utilization (calculate-hop-utilization potential-gravity (:time hop))
- alpha-acid-units (calculate-alpha-acid-units (:amount hop) (:alpha hop))
- imperial-volume (volume/convert batch-size options/litre options/american-gallon)
- conversion-factor 74.89]
- (/ (* alpha-acid-units utilization conversion-factor) imperial-volume)))
+ [{:keys [time amount alpha] :as _hop} batch-size potential-gravity]
+ (if (and (number? time)
+ (number? amount)
+ (number? alpha)
+ (number? batch-size)
+ (number? potential-gravity))
+ (let [utilization (calculate-hop-utilization potential-gravity time)
+ alpha-acid-units (calculate-alpha-acid-units amount alpha)
+ imperial-volume (volume/convert batch-size options/litre options/american-gallon)
+ conversion-factor 74.89]
+ (/ (* alpha-acid-units utilization conversion-factor) imperial-volume))
+ (throw (ex-info "Cannot calculate IBUs with non-numeric values" {:amount amount
+ :time time
+ :alpha alpha
+ :batch-size batch-size
+ :potential-gravity potential-gravity}))))
(defn calculate-recipe-ibus
- "Given a collection of `common-beer-format` conforming `hops`, `batch-size`, and `potential-gravity` calculate the amount of IBUs generated."
+ "Given a collection of `common-beer-format` conforming `hops`, `batch-size`, and `potential-gravity` calculate the amount of IBUs generated.
+ If insufficient data is provided, this function will throw an exception."
{:added "1.0"}
[hops batch-size potential-gravity]
(let [reducing-fn (fn [acc h] (+ acc (calculate-ibu-per-hop h batch-size potential-gravity)))]
@@ -206,7 +236,10 @@
(defn calculate-equipment-boil-volume
"Given a `common-beer-format` conforming `equipment`, calculate the volume of the wort at the start of the boil.
If insufficient data is provided, this function will throw an exception."
- {:added "1.5"}
+ {:added "1.5"
+ :see-also ["brewtility.enrich.equipment/enrich-calculated-boil-size"
+ "brewtility.enrich.equipment/enrich-equipment"
+ "brewtility.enrich.equipment/enrich-equipment-wrapper"]}
[{:keys [batch-size top-up-water trub-chiller-loss boil-time evap-rate]}]
(if (every? number? [batch-size top-up-water trub-chiller-loss boil-time evap-rate])
(let [starting-water (- batch-size top-up-water trub-chiller-loss)
diff --git a/src/brewtility/enrich/equipment.cljc b/src/brewtility/enrich/equipment.cljc
new file mode 100644
index 0000000..add804d
--- /dev/null
+++ b/src/brewtility/enrich/equipment.cljc
@@ -0,0 +1,486 @@
+(ns brewtility.enrich.equipment
+ "Enricher-pattern functions for [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) maps."
+ {:added "2.1"
+ :see-also ["brewtility.enrich.fermentables"
+ "brewtility.enrich.hops"
+ "brewtility.enrich.mash"
+ "brewtility.enrich.miscs"
+ "brewtility.enrich.recipes"
+ "brewtility.enrich.styles"
+ "brewtility.enrich.waters"
+ "brewtility.enrich.yeast"]}
+ (:require [brewtility.calculations :as calc]
+ [brewtility.enrich.impl :as impl]
+ [brewtility.precision :as precision]
+ [brewtility.units.options :as options]))
+
+
+(defn enrich-calculated-boil-size
+ "An enricher pattern function to calculate the boil size to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record via [[brewtility.calculations/calculate-equipment-boil-volume]].
+ In the BeerXML spec, this behavior is controlled by the `:calc-boil-volume` field.
+ When `:calc-boil-volume` is set to `true`, the `:boil-size` field is calculated as:
+ `(batch-size - top-up-water - trub-chiller-loss) * (1 + (boil-time * evap-rate))`
+
+ When `:calc-boil-volume` is set to `false`, the `:boil-size` field is left unmodified.
+ As a note, both the BeerXML spec and common-beer-format only require the `boil-size` field to be a number.
+ Neither the specification nor the implementation will check to ensure the value is correct given the other fields.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:safe-calculating-boil-size` - If this value is true, the program will not throw an exception if data is missing for the calculation.
+ In that case, the exception will be caught internally and the `:boil-size` will not be modified from its original value.
+ Defaults to `false`.
+ - `:precision` - The number of decimal places to round the calculated value to.
+ Defaults to `3`."
+ {:added "2.1"
+ :see-also ["brewtility.calculations/calculate-equipment-boil-volume"
+ "enrich-equipment"
+ "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-calculated-boil-size equipment {}))
+ ([{:keys [calc-boil-volume]
+ :as equipment}
+ {:keys [safe-calculating-boil-size precision]
+ :or {precision options/default-precision}}]
+ (try
+ (if calc-boil-volume
+ (let [derived-boil-size (precision/->precision (calc/calculate-equipment-boil-volume equipment) precision)]
+ (assoc equipment :boil-size derived-boil-size))
+ equipment)
+ #?(:clj (catch Exception e
+ (if safe-calculating-boil-size
+ equipment
+ (throw e))))
+ #?(:cljs (catch js/Error e
+ (if safe-calculating-boil-size
+ equipment
+ (throw e)))))))
+
+
+(defn enrich-display-boil-size
+ "An enricher pattern function to add the displayable boil size to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:system-of-measure`: The unit system of measure to convert the boil size into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the boil size. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained selections within the context of `enrich-equipment` and `enrich-equipment-wrapper`, this function also supports the following keys:
+ - `:boil-size-target-units`: The unit to convert the boil size into. Supersedes `:system-of-measure`.
+ - `:boil-size-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:boil-size-suffix`: The suffix type to append to the boil size. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-equipment" "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-display-boil-size equipment {}))
+ ([equipment
+ {:keys [boil-size-target-units boil-size-precision boil-size-suffix]
+ :as opts}]
+ (let [options (merge opts
+ {impl/value-key :boil-size
+ impl/display-key :display-boil-size
+ impl/fine-grain-target-units boil-size-target-units
+ impl/fine-grain-precision boil-size-precision
+ impl/fine-grain-suffix boil-size-suffix})]
+ (impl/enrich-displayable-units options/volume equipment options))))
+
+
+(defn enrich-display-batch-size
+ "An enricher pattern function to add the displayable batch size to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:system-of-measure`: The unit system of measure to convert the batch size into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the batch size. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained selections within the context of `enrich-equipment` and `enrich-equipment-wrapper`, this function also supports the following keys:
+ - `:batch-size-target-units`: The unit to convert the batch size into. Supersedes `:system-of-measure`.
+ - `:batch-size-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:batch-size-suffix`: The suffix type to append to the batch size. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-equipment" "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-display-batch-size equipment {}))
+ ([equipment
+ {:keys [batch-size-target-units batch-size-precision batch-size-suffix]
+ :as opts}]
+ (let [options (merge opts
+ {impl/value-key :batch-size
+ impl/display-key :display-batch-size
+ impl/fine-grain-target-units batch-size-target-units
+ impl/fine-grain-precision batch-size-precision
+ impl/fine-grain-suffix batch-size-suffix})]
+ (impl/enrich-displayable-units options/volume equipment options))))
+
+
+(defn enrich-display-tun-volume
+ "An enricher pattern function to add the displayable tun volume to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:system-of-measure`: The unit system of measure to convert the tun volume into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the tun volume. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained selections within the context of `enrich-equipment` and `enrich-equipment-wrapper`, this function also supports the following keys:
+ - `:tun-volume-target-units`: The unit to convert the tun volume into. Supersedes `:system-of-measure`.
+ - `:tun-volume-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:tun-volume-suffix`: The suffix type to append to the tun volume. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-equipment" "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-display-tun-volume equipment {}))
+ ([equipment
+ {:keys [tun-volume-target-units tun-volume-precision tun-volume-suffix]
+ :as opts}]
+ (let [options (merge opts
+ {impl/value-key :tun-volume
+ impl/display-key :display-tun-volume
+ impl/fine-grain-target-units tun-volume-target-units
+ impl/fine-grain-precision tun-volume-precision
+ impl/fine-grain-suffix tun-volume-suffix})]
+ (impl/enrich-displayable-units options/volume equipment options))))
+
+
+(defn enrich-display-tun-weight
+ "An enricher pattern function to add the displayable tun weight to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:system-of-measure`: The unit system of measure to convert the tun weight into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the tun weight. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-equipment` and `enrich-equipment-wrapper`, this function also supports the following keys:
+ - `:tun-weight-target-units`: The unit to convert the tun weight into. Supersedes `:system-of-measure`.
+ - `:tun-weight-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:tun-weight-suffix`: The suffix type to append to the tun weight. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-equipment" "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-display-tun-weight equipment {}))
+ ([equipment
+ {:keys [tun-weight-target-units tun-weight-precision tun-weight-suffix]
+ :as opts}]
+ (let [options (merge opts
+ {impl/value-key :tun-weight
+ impl/display-key :display-tun-weight
+ impl/fine-grain-target-units tun-weight-target-units
+ impl/fine-grain-precision tun-weight-precision
+ impl/fine-grain-suffix tun-weight-suffix})]
+ (impl/enrich-displayable-units options/weight equipment options))))
+
+
+(defn enrich-display-top-up-water
+ "An enricher pattern function to add the displayable top up water to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:system-of-measure`: The unit system of measure to convert the top up water into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the top up water. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained selections within the context of `enrich-equipment` and `enrich-equipment-wrapper`, this function also supports the following keys:
+ - `:top-up-water-target-units`: The unit to convert the top up water into. Supersedes `:system-of-measure`.
+ - `:top-up-water-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:top-up-water-suffix`: The suffix type to append to the top up water. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-equipment" "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-display-top-up-water equipment {}))
+ ([equipment
+ {:keys [top-up-water-target-units top-up-water-precision top-up-water-suffix]
+ :as opts}]
+ (let [options (merge opts
+ {impl/value-key :top-up-water
+ impl/display-key :display-top-up-water
+ impl/fine-grain-target-units top-up-water-target-units
+ impl/fine-grain-precision top-up-water-precision
+ impl/fine-grain-suffix top-up-water-suffix})]
+ (impl/enrich-displayable-units options/volume equipment options))))
+
+
+(defn enrich-display-trub-chiller-loss
+ "An enricher pattern function to add the displayable trub chiller loss to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:system-of-measure`: The unit system of measure to convert the trub chiller loss into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the trub chiller loss. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained selections within the context of `enrich-equipment` and `enrich-equipment-wrapper`, this function also supports the following keys:
+ - `:trub-chiller-loss-target-units`: The unit to convert the trub chiller loss into. Supersedes `:system-of-measure`.
+ - `:trub-chiller-loss-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:trub-chiller-loss-suffix`: The suffix type to append to the trub chiller loss. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-equipment" "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-display-trub-chiller-loss equipment {}))
+ ([equipment
+ {:keys [trub-chiller-loss-target-units trub-chiller-loss-precision trub-chiller-loss-suffix]
+ :as opts}]
+ (let [options (merge opts
+ {impl/value-key :trub-chiller-loss
+ impl/display-key :display-trub-chiller-loss
+ impl/fine-grain-target-units trub-chiller-loss-target-units
+ impl/fine-grain-precision trub-chiller-loss-precision
+ impl/fine-grain-suffix trub-chiller-loss-suffix})]
+ (impl/enrich-displayable-units options/volume equipment options))))
+
+
+(defn enrich-display-lauter-deadspace
+ "An enricher pattern function to add the displayable lauter deadspace to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:system-of-measure`: The unit system of measure to convert the lauter deadspace into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the lauter deadspace. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained selections within the context of `enrich-equipment` and `enrich-equipment-wrapper`, this function also supports the following keys:
+ - `:lauter-deadspace-target-units`: The unit to convert the lauter deadspace into. Supersedes `:system-of-measure`.
+ - `:lauter-deadspace-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:lauter-deadspace-suffix`: The suffix type to append to the lauter deadspace. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-equipment" "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-display-lauter-deadspace equipment {}))
+ ([equipment
+ {:keys [lauter-deadspace-target-units lauter-deadspace-precision lauter-deadspace-suffix]
+ :as opts}]
+ (let [options (merge opts
+ {impl/value-key :lauter-deadspace
+ impl/display-key :display-lauter-deadspace
+ impl/fine-grain-target-units lauter-deadspace-target-units
+ impl/fine-grain-precision lauter-deadspace-precision
+ impl/fine-grain-suffix lauter-deadspace-suffix})]
+ (impl/enrich-displayable-units options/volume equipment options))))
+
+
+(defn enrich-display-top-up-kettle
+ "An enricher pattern function to add the displayable top up kettle to an [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) record.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported:
+
+ - `:system-of-measure`: The unit system of measure to convert the top up kettle into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the top up kettle. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained selections within the context of `enrich-equipment` and `enrich-equipment-wrapper`, this function also supports the following keys:
+ - `:top-up-kettle-target-units`: The unit to convert the top up kettle into. Supersedes `:system-of-measure`.
+ - `:top-up-kettle-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:top-up-kettle-suffix`: The suffix type to append to the top up kettle. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-equipment" "enrich-equipment-wrapper"]}
+ ([equipment] (enrich-display-top-up-kettle equipment {}))
+ ([equipment
+ {:keys [top-up-kettle-target-units top-up-kettle-precision top-up-kettle-suffix]
+ :as opts}]
+ (let [options (merge opts
+ {impl/value-key :top-up-kettle
+ impl/display-key :display-top-up-kettle
+ impl/fine-grain-target-units top-up-kettle-target-units
+ impl/fine-grain-precision top-up-kettle-precision
+ impl/fine-grain-suffix top-up-kettle-suffix})]
+ (impl/enrich-displayable-units options/volume equipment options))))
+
+
+(defn enrich-equipment
+ "An enricher pattern function to derive as many values from an [equipment record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the displayable fields into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the displayable fields. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-calculated-boil-size]]
+ - `:safe-calculating-boil-size` - If this value is true, the program will not throw an exception if data is missing for the calculation.
+ In that case, the exception will be caught internally and the `:boil-size` will not be modified from its original value.
+ Defaults to `false`.
+ - [[enrich-display-boil-size]]
+ - `:boil-size-target-units`: The unit to convert the boil size into. Supersedes `:system-of-measure`.
+ - `:boil-size-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:boil-size-suffix`: The suffix type to append to the boil size. Supersedes `:suffix`.
+ - [[enrich-display-batch-size]]
+ - `:batch-size-target-units`: The unit to convert the batch size into. Supersedes `:system-of-measure`.
+ - `:batch-size-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:batch-size-suffix`: The suffix type to append to the batch size. Supersedes `:suffix`.
+ - [[enrich-diplay-tun-volume]]
+ - `:tun-volume-target-units`: The unit to convert the tun volume into. Supersedes `:system-of-measure`.
+ - `:tun-volume-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:tun-volume-suffix`: The suffix type to append to the tun volume. Supersedes `:suffix`.
+ - [[enrich-display-tun-weight]]
+ - `:tun-weight-target-units`: The unit to convert the tun weight into. Supersedes `:system-of-measure`.
+ - `:tun-weight-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:tun-weight-suffix`: The suffix type to append to the tun weight. Supersedes `:suffix`.
+ - [[enrich-display-top-up-water]]
+ - `:top-up-water-target-units`: The unit to convert the top up water into. Supersedes `:system-of-measure`.
+ - `:top-up-water-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:top-up-water-suffix`: The suffix type to append to the top up water. Supersedes `:suffix`.
+ - [[enrich-display-trub-chiller-loss]]
+ - `:trub-chiller-loss-target-units`: The unit to convert the trub chiller loss into. Supersedes `:system-of-measure`.
+ - `:trub-chiller-loss-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:trub-chiller-loss-suffix`: The suffix type to append to the trub chiller loss. Supersedes `:suffix`.
+ - [[enrich-display-lauter-deadspace]]
+ - `:lauter-deadspace-target-units`: The unit to convert the lauter deadspace into. Supersedes `:system-of-measure`.
+ - `:lauter-deadspace-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:lauter-deadspace-suffix`: The suffix type to append to the lauter deadspace. Supersedes `:suffix`.
+ - [[enrich-display-top-up-kettle]]
+ - `:top-up-kettle-target-units`: The unit to convert the top up kettle into. Supersedes `:system-of-measure`.
+ - `:top-up-kettle-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:top-up-kettle-suffix`: The suffix type to append to the top up kettle. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-calculated-boil-size"
+ "enrich-calculated-boil-size"
+ "enrich-diplay-tun-volume"
+ "enrich-display-tun-weight"
+ "enrich-display-top-up-water"
+ "enrich-display-trub-chiller-loss"
+ "enrich-display-lauter-deadspace"
+ "enrich-display-top-up-kettle"
+ "enrich-equipment-wrapper"]}
+ ([equipment]
+ (enrich-equipment equipment {}))
+
+ ([equipment opts]
+ (-> equipment
+ (enrich-calculated-boil-size opts)
+ (enrich-display-boil-size opts)
+ (enrich-display-batch-size opts)
+ (enrich-display-tun-volume opts)
+ (enrich-display-tun-weight opts)
+ (enrich-display-top-up-water opts)
+ (enrich-display-trub-chiller-loss opts)
+ (enrich-display-lauter-deadspace opts)
+ (enrich-display-top-up-kettle opts))))
+
+
+(defn enrich-equipment-wrapper
+ "An enricher pattern function to derive as many values from an [equipment-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the displayable fields into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the displayable fields. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
+ - `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-calculated-boil-size]]
+ - `:safe-calculating-boil-size` - If this value is true, the program will not throw an exception if data is missing for the calculation.
+ In that case, the exception will be caught internally and the `:boil-size` will not be modified from its original value.
+ Defaults to `false`.
+ - [[enrich-display-boil-size]]
+ - `:boil-size-target-units`: The unit to convert the boil size into. Supersedes `:system-of-measure`.
+ - `:boil-size-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:boil-size-suffix`: The suffix type to append to the boil size. Supersedes `:suffix`.
+ - [[enrich-display-batch-size]]
+ - `:batch-size-target-units`: The unit to convert the batch size into. Supersedes `:system-of-measure`.
+ - `:batch-size-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:batch-size-suffix`: The suffix type to append to the batch size. Supersedes `:suffix`.
+ - [[enrich-diplay-tun-volume]]
+ - `:tun-volume-target-units`: The unit to convert the tun volume into. Supersedes `:system-of-measure`.
+ - `:tun-volume-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:tun-volume-suffix`: The suffix type to append to the tun volume. Supersedes `:suffix`.
+ - [[enrich-display-tun-weight]]
+ - `:tun-weight-target-units`: The unit to convert the tun weight into. Supersedes `:system-of-measure`.
+ - `:tun-weight-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:tun-weight-suffix`: The suffix type to append to the tun weight. Supersedes `:suffix`.
+ - [[enrich-display-top-up-water]]
+ - `:top-up-water-target-units`: The unit to convert the top up water into. Supersedes `:system-of-measure`.
+ - `:top-up-water-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:top-up-water-suffix`: The suffix type to append to the top up water. Supersedes `:suffix`.
+ - [[enrich-display-trub-chiller-loss]]
+ - `:trub-chiller-loss-target-units`: The unit to convert the trub chiller loss into. Supersedes `:system-of-measure`.
+ - `:trub-chiller-loss-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:trub-chiller-loss-suffix`: The suffix type to append to the trub chiller loss. Supersedes `:suffix`.
+ - [[enrich-display-lauter-deadspace]]
+ - `:lauter-deadspace-target-units`: The unit to convert the lauter deadspace into. Supersedes `:system-of-measure`.
+ - `:lauter-deadspace-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:lauter-deadspace-suffix`: The suffix type to append to the lauter deadspace. Supersedes `:suffix`.
+ - [[enrich-display-top-up-kettle]]
+ - `:top-up-kettle-target-units`: The unit to convert the top up kettle into. Supersedes `:system-of-measure`.
+ - `:top-up-kettle-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:top-up-kettle-suffix`: The suffix type to append to the top up kettle. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-calculated-boil-size"
+ "enrich-calculated-boil-size"
+ "enrich-diplay-tun-volume"
+ "enrich-display-tun-weight"
+ "enrich-display-top-up-water"
+ "enrich-display-trub-chiller-loss"
+ "enrich-display-lauter-deadspace"
+ "enrich-display-top-up-kettle"
+ "enrich-equipment"]}
+ ([equipment-wrapper]
+ (enrich-equipment-wrapper equipment-wrapper {}))
+
+ ([equipment-wrapper opts]
+ (update equipment-wrapper :equipment enrich-equipment opts)))
diff --git a/src/brewtility/enrich/fermentables.cljc b/src/brewtility/enrich/fermentables.cljc
new file mode 100644
index 0000000..446476b
--- /dev/null
+++ b/src/brewtility/enrich/fermentables.cljc
@@ -0,0 +1,461 @@
+(ns brewtility.enrich.fermentables
+ "Enricher-pattern functions for [fermentables](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) maps"
+ {:added "2.1"
+ :see-also ["brewtility.enrich.equipment"
+ "brewtility.enrich.hops"
+ "brewtility.enrich.mash"
+ "brewtility.enrich.miscs"
+ "brewtility.enrich.recipes"
+ "brewtility.enrich.styles"
+ "brewtility.enrich.waters"
+ "brewtility.enrich.yeast"]}
+ (:require [brewtility.enrich.impl :as impl]
+ [brewtility.predicates.fermentables :as fermentables.predicate]
+ [brewtility.units.options :as options]))
+
+
+(defn enrich-add-after-boil
+ "An enricher pattern function to determine if a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) was added after the boil.
+ In the BeerXML spec, this behavior is implicitly falsey.
+ Therefore, if the :add-after-boil field is not present, this function will explicitly set it to false."
+ {:added "2.1"
+ :see-also ["enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-add-after-boil fermentable {}))
+ ([fermentable _opts] ; Used to maintain signature parity with enricher pattern functions
+ (if (contains? fermentable :add-after-boil)
+ fermentable
+ (assoc fermentable :add-after-boil false))))
+
+
+(defn enrich-coarse-fine-diff
+ "An enricher pattern function to determine if a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) should have a coarse/fine differential.
+ In the BeerXML spec, this field is only valid if the `:type` of the fermentable is `grain` or `adjunct`.
+ When the fermetable is not a grain or adjunct, this function will dissoc `:coarse-fine-diff` from the fermentable.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false."
+ {:added "2.1"
+ :see-also ["brewtility.predicates.fermentables/grain?"
+ "brewtility.predicates.fermentables/adjunct?"
+ "enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-coarse-fine-diff fermentable {}))
+ ([fermentable opts]
+ (if (or (fermentables.predicate/grain? fermentable opts)
+ (fermentables.predicate/adjunct? fermentable opts))
+ fermentable
+ (dissoc fermentable :coarse-fine-diff))))
+
+
+(defn enrich-moisture
+ "An enricher pattern function to determine if a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) should have a moisture content.
+ In the BeerXML spec, this field is only valid if the `:type` of the fermentable is `grain` or `adjunct`.
+ When the fermetable is not a grain or adjunct, this function will dissoc `:moisture` from the fermentable.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false."
+ {:added "2.1"
+ :see-also ["brewtility.predicates.fermentables/grain?"
+ "brewtility.predicates.fermentables/adjunct?"
+ "enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-moisture fermentable {}))
+ ([fermentable opts]
+ (if (or (fermentables.predicate/grain? fermentable opts)
+ (fermentables.predicate/adjunct? fermentable opts))
+ fermentable
+ (dissoc fermentable :moisture))))
+
+
+(defn enrich-diastatic-power
+ "An enricher pattern function to determine if a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) should have a listed Diastatic Power.
+ In the BeerXML spec, this field is only valid if the `:type` of the fermentable is `grain` or `adjunct`.
+ When the fermetable is not a grain or adjunct, this function will dissoc `:diastatic-power` from the fermentable.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false."
+ {:added "2.1"
+ :see-also ["brewtility.predicates.fermentables/grain?"
+ "brewtility.predicates.fermentables/adjunct?"
+ "enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-diastatic-power fermentable {}))
+ ([fermentable opts]
+ (if (or (fermentables.predicate/grain? fermentable opts)
+ (fermentables.predicate/adjunct? fermentable opts))
+ fermentable
+ (dissoc fermentable :diastatic-power))))
+
+
+(defn enrich-protein
+ "An enricher pattern function to determine if a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) should have protein.
+ In the BeerXML spec, this field is only valid if the `:type` of the fermentable is `grain` or `adjunct`.
+ When the fermetable is not a grain or adjunct, this function will dissoc `:protein` from the fermentable.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false."
+ {:added "2.1"
+ :see-also ["brewtility.predicates.fermentables/grain?"
+ "brewtility.predicates.fermentables/adjunct?"
+ "enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-protein fermentable {}))
+ ([fermentable opts]
+ (if (or (fermentables.predicate/grain? fermentable opts)
+ (fermentables.predicate/adjunct? fermentable opts))
+ fermentable
+ (dissoc fermentable :protein))))
+
+
+(defn enrich-recommend-mash
+ "An enricher pattern function to determine if a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) should have recommend-mash.
+ In the BeerXML spec, this field should only be `true` if the `:type` of the fermentable is `grain` or `adjunct`.
+ When the fermetable is not a grain or adjunct, this function will set `:recommend-mash` to false in the fermentable.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false."
+ {:added "2.1"
+ :see-also ["brewtility.predicates.fermentables/grain?"
+ "brewtility.predicates.fermentables/adjunct?"
+ "enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-recommend-mash fermentable {}))
+ ([fermentable opts]
+ (if (or (fermentables.predicate/grain? fermentable opts)
+ (fermentables.predicate/adjunct? fermentable opts))
+ (assoc fermentable :recommend-mash true)
+ (assoc fermentable :recommend-mash false))))
+
+
+(defn enrich-ibu-gallons-per-pound
+ "An enricher pattern function to determine if a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) should have ibu-gal-per-lb.
+ In the BeerXML spec, this field is only valid if the `:type` of the fermentable is `extract`.
+ When the fermetable is not an extract, this function will dissoc `:ibu-gal-per-lb` from the fermentable.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false."
+ {:added "2.1"
+ :see-also ["brewtility.predicates.fermentables/extract?"
+ "enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-ibu-gallons-per-pound fermentable {}))
+ ([fermentable opts]
+ (if (fermentables.predicate/extract? fermentable opts)
+ fermentable
+ (dissoc fermentable :ibu-gal-per-lb))))
+
+
+(defn enrich-display-color
+ "An enricher pattern function to determine what color a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) is in a given system.
+ In the BeerXML spec, color is assumed to be in Lovibond for the `:type` of `grain`, and SRM for all other fermentables.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:color-system` - The color system to use for the conversion. Default is `:lovibond` for type `:grain`, and `:srm` otherwise. Acceptable values are:
+ - `:lovibond` - Use the [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour) system.
+ - `:srm` - Use the [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method) system.
+ - `:ebc` - Use the [European Brewing Convention](https://www.lovibond.com/en/PC/Colour-Measurement/Colour-Scales-Standards/EBC-European-Brewing-Convention) system.
+ - `:rgba` - USe the [RGBa](https://www.w3schools.com/cssref/func_rgba.asp) color system, commonly used in CSS.
+ - `:suffix`: The suffix type to append to the boil size. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained selections within the context of `enrich-fermentable` and `enrich-fermentable-wrapper`, this function also supports the following keys:
+ - `:fermentable-color-target-units`: The unit to convert the color into. Supersedes `:color-system`.
+ - `:fermentable-color-precision`: The number of significant decimal places to display. Supersedes `:color`.
+ - `:fermentable-color-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-display-color fermentable {}))
+ ([fermentable {:keys [color-system
+ fermentable-color-target-units
+ fermentable-color-precision
+ fermentable-color-suffix]
+ :as opts}]
+ (let [source-color-system (if (fermentables.predicate/grain? fermentable opts)
+ options/lovibond
+ options/srm)
+ color-system (or color-system source-color-system)
+ opts (merge opts {:source-units source-color-system
+ impl/value-key :color
+ impl/display-key :display-color
+ impl/fine-grain-target-units (or fermentable-color-target-units color-system)
+ impl/fine-grain-precision fermentable-color-precision
+ impl/fine-grain-suffix fermentable-color-suffix})]
+ (impl/enrich-displayable-units options/color fermentable opts))))
+
+
+(defn enrich-display-amount
+ "An enricher pattern function to render a human-readable display weight of a [fermentable](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc) is in a given system.
+ In the BeerXML spec, the amount of a liquid extract is computed by its weight.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-fermentable` and `enrich-fermentable-wrapper`, this function also supports the following keys:
+ - `:fermentable-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:fermentable-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:fermentable-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-fermentable"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-display-amount fermentable {}))
+ ([fermentable {:keys [fermentable-amount-target-units
+ fermentable-amount-precision
+ fermentable-amount-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :amount
+ impl/display-key :display-amount
+ impl/fine-grain-target-units fermentable-amount-target-units
+ impl/fine-grain-precision fermentable-amount-precision
+ impl/fine-grain-suffix fermentable-amount-suffix})]
+ (impl/enrich-displayable-units options/weight fermentable options))))
+
+
+(defn enrich-fermentable
+ "An enricher pattern function to derive as many values from an [fermentable record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false.
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+ - `:color-system` - The color system to use for the conversion. Default is `:lovibond` for type `:grain`, and `:srm` otherwise. Acceptable values are:
+ - `:lovibond` - Use the [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour) system.
+ - `:srm` - Use the [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method) system.
+ - `:ebc` - Use the [European Brewing Convention](https://www.lovibond.com/en/PC/Colour-Measurement/Colour-Scales-Standards/EBC-European-Brewing-Convention) system.
+ - `:rgba` - USe the [RGBa](https://www.w3schools.com/cssref/func_rgba.asp) color system, commonly used in CSS.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-color]]
+ - `:fermentable-color-target-units`: The unit to convert the color into. Supersedes `:color-system`.
+ - `:fermentable-color-precision`: The number of significant decimal places to display. Supersedes `:color`.
+ - `:fermentable-color-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-amount]]
+ - `:fermentable-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:fermentable-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:fermentable-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-add-after-boil"
+ "enrich-coarse-fine-diff"
+ "enrich-moisture"
+ "enrich-diastatic-power"
+ "enrich-protein"
+ "enrich-recommend-mash"
+ "enrich-ibu-gallons-per-pound"
+ "enrich-display-color"
+ "enrich-display-amount"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-fermentable fermentable {}))
+ ([fermentable opts]
+ (-> fermentable
+ (enrich-add-after-boil opts)
+ (enrich-coarse-fine-diff opts)
+ (enrich-moisture opts)
+ (enrich-diastatic-power opts)
+ (enrich-protein opts)
+ (enrich-recommend-mash opts)
+ (enrich-ibu-gallons-per-pound opts)
+ (enrich-display-color opts)
+ (enrich-display-amount opts))))
+
+
+(defn enrich-fermentable-wrapper
+ "An enricher pattern function to derive as many values from an [fermentable-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false.
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+ - `:color-system` - The color system to use for the conversion. Default is `:lovibond` for type `:grain`, and `:srm` otherwise. Acceptable values are:
+ - `:lovibond` - Use the [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour) system.
+ - `:srm` - Use the [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method) system.
+ - `:ebc` - Use the [European Brewing Convention](https://www.lovibond.com/en/PC/Colour-Measurement/Colour-Scales-Standards/EBC-European-Brewing-Convention) system.
+ - `:rgba` - USe the [RGBa](https://www.w3schools.com/cssref/func_rgba.asp) color system, commonly used in CSS.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-color]]
+ - `:fermentable-color-target-units`: The unit to convert the color into. Supersedes `:color-system`.
+ - `:fermentable-color-precision`: The number of significant decimal places to display. Supersedes `:color`.
+ - `:fermentable-color-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-amount]]
+ - `:fermentable-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:fermentable-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:fermentable-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-add-after-boil"
+ "enrich-coarse-fine-diff"
+ "enrich-moisture"
+ "enrich-diastatic-power"
+ "enrich-protein"
+ "enrich-recommend-mash"
+ "enrich-ibu-gallons-per-pound"
+ "enrich-display-color"
+ "enrich-display-amount"
+ "enrich-fermentable"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentable] (enrich-fermentable-wrapper fermentable {}))
+ ([fermentable opts]
+ (update fermentable :fermentable enrich-fermentable opts)))
+
+
+(defn enrich-fermentables
+ "An enricher pattern function to derive as many values from an [fermentables record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false.
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+ - `:color-system` - The color system to use for the conversion. Default is `:lovibond` for type `:grain`, and `:srm` otherwise. Acceptable values are:
+ - `:lovibond` - Use the [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour) system.
+ - `:srm` - Use the [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method) system.
+ - `:ebc` - Use the [European Brewing Convention](https://www.lovibond.com/en/PC/Colour-Measurement/Colour-Scales-Standards/EBC-European-Brewing-Convention) system.
+ - `:rgba` - USe the [RGBa](https://www.w3schools.com/cssref/func_rgba.asp) color system, commonly used in CSS.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-color]]
+ - `:fermentable-color-target-units`: The unit to convert the color into. Supersedes `:color-system`.
+ - `:fermentable-color-precision`: The number of significant decimal places to display. Supersedes `:color`.
+ - `:fermentable-color-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-amount]]
+ - `:fermentable-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:fermentable-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:fermentable-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-add-after-boil"
+ "enrich-coarse-fine-diff"
+ "enrich-moisture"
+ "enrich-diastatic-power"
+ "enrich-protein"
+ "enrich-recommend-mash"
+ "enrich-ibu-gallons-per-pound"
+ "enrich-display-color"
+ "enrich-display-amount"
+ "enrich-fermentable-wrapper"
+ "enrich-fermentable"
+ "enrich-fermentables-wrapper"]}
+ ([fermentables] (enrich-fermentables fermentables {}))
+ ([fermentables opts]
+ (map #(enrich-fermentable-wrapper % opts) fermentables)))
+
+
+(defn enrich-fermentables-wrapper
+ "An enricher pattern function to derive as many values from an [fermentables-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/fermentables.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false.
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+ - `:color-system` - The color system to use for the conversion. Default is `:lovibond` for type `:grain`, and `:srm` otherwise. Acceptable values are:
+ - `:lovibond` - Use the [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour) system.
+ - `:srm` - Use the [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method) system.
+ - `:ebc` - Use the [European Brewing Convention](https://www.lovibond.com/en/PC/Colour-Measurement/Colour-Scales-Standards/EBC-European-Brewing-Convention) system.
+ - `:rgba` - USe the [RGBa](https://www.w3schools.com/cssref/func_rgba.asp) color system, commonly used in CSS.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-color]]
+ - `:fermentable-color-target-units`: The unit to convert the color into. Supersedes `:color-system`.
+ - `:fermentable-color-precision`: The number of significant decimal places to display. Supersedes `:color`.
+ - `:fermentable-color-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-amount]]
+ - `:fermentable-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:fermentable-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:fermentable-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-add-after-boil"
+ "enrich-coarse-fine-diff"
+ "enrich-moisture"
+ "enrich-diastatic-power"
+ "enrich-protein"
+ "enrich-recommend-mash"
+ "enrich-ibu-gallons-per-pound"
+ "enrich-display-color"
+ "enrich-display-amount"
+ "enrich-fermentable"
+ "enrich-fermentables"
+ "enrich-fermentables-wrapper"]}
+ ([fermentables] (enrich-fermentables-wrapper fermentables {}))
+ ([fermentables opts]
+ (update fermentables :fermentables enrich-fermentables opts)))
diff --git a/src/brewtility/enrich/hops.cljc b/src/brewtility/enrich/hops.cljc
new file mode 100644
index 0000000..6370a47
--- /dev/null
+++ b/src/brewtility/enrich/hops.cljc
@@ -0,0 +1,237 @@
+(ns brewtility.enrich.hops
+ "Enricher-pattern functions for [hops](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc) maps"
+ {:added "2.1"
+ :see-also ["brewtility.enrich.equipment"
+ "brewtility.enrich.fermentables"
+ "brewtility.enrich.mash"
+ "brewtility.enrich.miscs"
+ "brewtility.enrich.recipes"
+ "brewtility.enrich.styles"
+ "brewtility.enrich.waters"
+ "brewtility.enrich.yeast"]}
+ (:require [brewtility.enrich.impl :as impl]
+ [brewtility.units.options :as options]))
+
+
+(defn enrich-display-amount
+ "An enricher pattern function to render a human-readable display weight of a [hop](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-hop` and `enrich-hop-wrapper`, this function also supports the following keys:
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["brewtility.string/same?"
+ "enrich-hop"
+ "enrich-hop-wrapper"
+ "enrich-hops"
+ "enrich-hops-wrapper"]}
+ ([hop] (enrich-display-amount hop {}))
+ ([hop {:keys [hop-amount-target-units
+ hop-amount-precision
+ hop-amount-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :amount
+ impl/display-key :display-amount
+ impl/fine-grain-target-units hop-amount-target-units
+ impl/fine-grain-precision hop-amount-precision
+ impl/fine-grain-suffix hop-amount-suffix})]
+ (impl/enrich-displayable-units options/weight hop options))))
+
+
+(defn enrich-display-time
+ "An enricher pattern function to render a human-readable display time of a [hop](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the time into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the time Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-hop` and `enrich-hop-wrapper`, this function also supports the following keys:
+ - `:hop-time-target-units`: The unit to convert the time into. Supersedes `:system-of-measure`.
+ - `:hop-time-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-time-suffix`: The suffix type to append to the time. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-hop"
+ "enrich-hop-wrapper"
+ "enrich-hops"
+ "enrich-hops-wrapper"]}
+ ([hop] (enrich-display-time hop {}))
+ ([hop {:keys [hop-time-target-units
+ hop-time-precision
+ hop-time-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :time
+ impl/display-key :display-time
+ impl/fine-grain-target-units hop-time-target-units
+ impl/fine-grain-precision hop-time-precision
+ impl/fine-grain-suffix hop-time-suffix})]
+ (impl/enrich-displayable-units options/time hop options))))
+
+
+(defn enrich-hop
+ "An enricher pattern function to derive as many values from an [hop record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-display-time"
+ "enrich-hop-wrapper"
+ "enrich-hops"
+ "enrich-hops-wrapper"]}
+ ([hop] (enrich-hop hop {}))
+ ([hop opts]
+ (-> hop
+ (enrich-display-amount opts)
+ (enrich-display-time opts))))
+
+
+(defn enrich-hop-wrapper
+ "An enricher pattern function to derive as many values from an [hop-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-display-time"
+ "enrich-hop"
+ "enrich-hops"
+ "enrich-hops-wrapper"]}
+ ([hop] (enrich-hop-wrapper hop {}))
+ ([hop opts]
+ (update hop :hop enrich-hop opts)))
+
+
+(defn enrich-hops
+ "An enricher pattern function to derive as many values from an [hops record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-display-time"
+ "enrich-hop-wrapper"
+ "enrich-hop"
+ "enrich-hops-wrapper"]}
+ ([hops] (enrich-hops hops {}))
+ ([hops opts]
+ (map #(enrich-hop-wrapper % opts) hops)))
+
+
+(defn enrich-hops-wrapper
+ "An enricher pattern function to derive as many values from an [hops-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:hop-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:hop-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:hop-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-display-time"
+ "enrich-hop-wrapper"
+ "enrich-hops"
+ "enrich-hop"]}
+ ([hops] (enrich-hops-wrapper hops {}))
+ ([hops opts]
+ (update hops :hops enrich-hops opts)))
+
diff --git a/src/brewtility/enrich/impl.cljc b/src/brewtility/enrich/impl.cljc
new file mode 100644
index 0000000..4e1af5a
--- /dev/null
+++ b/src/brewtility/enrich/impl.cljc
@@ -0,0 +1,446 @@
+(ns brewtility.enrich.impl
+ "Function to help minimize repeated code in enricher functions.
+
+ Not intended for public consumption."
+ {:no-doc true
+ :added "2.1"
+ :implementation-only true}
+ (:require [brewtility.units :as units]
+ [brewtility.units.alcohol-content :as alcohol-content]
+ [brewtility.units.bitterness :as bitterness]
+ [brewtility.units.carbonation :as carbonation]
+ [brewtility.units.color :as color]
+ [brewtility.units.options :as options]
+ [brewtility.units.pressure :as pressure]
+ [brewtility.units.specific-gravity :as specific-gravity]
+ [brewtility.units.temperature :as temperature]
+ [brewtility.units.time :as time]
+ [brewtility.units.volume :as volume]
+ [brewtility.units.weight :as weight]))
+
+
+(def default-display-options
+ "The default display options used for all enrichers."
+ {options/precision options/default-precision
+ options/suffix options/short})
+
+
+(def value-key
+ "The key to source data from in `enrich-displayable-*` functions"
+ :value-key)
+
+
+(def low-value-key
+ "The key to source data from in `enrich-displayable-*` functions for the lower end of the range"
+ :low-value-key)
+
+
+(def high-value-key
+ "The key to source data from in `enrich-displayable-*` functions for the higher end of the range"
+ :high-value-key)
+
+
+(def display-key
+ "The key to store displayable data in in `-enrich-displayable-*` functions"
+ :display-key)
+
+
+(def fine-grain-target-units
+ "The target units to use for fine-grain toggling of displayable units in `enrich-displayable-*` functions"
+ :fine-grain-target-units)
+
+
+(def fine-grain-precision
+ "The suffix to use for fine-grain setting of precision in `-enrich-displayable-*` functions"
+ :fine-grain-precision)
+
+
+(def fine-grain-suffix
+ "The suffix to use for fine-grain setting of precision in `enrich-displayable-*` functions"
+ :fine-grain-suffix)
+
+
+(def default-alcohol-content-by-system
+ "The default alcohol content system to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/abv
+ options/metric options/abv
+ options/us-customary options/abv
+ options/international-system options/abv})
+
+
+(def default-bitterness-by-system
+ "The default bitterness to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/ibu
+ options/metric options/ibu
+ options/us-customary options/ibu
+ options/international-system options/ibu})
+
+
+(def default-carbonation-by-system
+ "The default carbonation to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/volumes-of-co2
+ options/metric options/volumes-of-co2
+ options/us-customary options/volumes-of-co2
+ options/international-system options/volumes-of-co2})
+
+
+(def default-color-by-system
+ "The default color to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/srm
+ options/metric options/srm
+ options/us-customary options/srm
+ options/international-system options/srm})
+
+
+(def default-pressure-by-system
+ "The default pressure to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/psi
+ options/metric options/kilopascal
+ options/us-customary options/psi
+ options/international-system options/kilopascal})
+
+
+(def default-specific-gravity-by-system
+ "The default specific gravity to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/specific-gravity
+ options/metric options/specific-gravity
+ options/us-customary options/specific-gravity
+ options/international-system options/specific-gravity})
+
+
+(def default-temperature-by-system
+ "The default temperature to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/fahrenheit
+ options/metric options/celsius
+ options/us-customary options/fahrenheit
+ options/international-system options/celsius})
+
+
+(def default-time-by-system
+ "The default time to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/minute
+ options/metric options/minute
+ options/us-customary options/minute
+ options/international-system options/minute})
+
+
+(def default-volume-by-system
+ "The default volume to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/imperial-gallon
+ options/metric options/litre
+ options/us-customary options/american-gallon
+ options/international-system options/litre})
+
+
+(def default-weight-by-system
+ "The default weight to use for each system in `enrich-displayable-*` functions."
+ {options/imperial options/pound
+ options/metric options/kilogram
+ options/us-customary options/pound
+ options/international-system options/kilogram})
+
+
+(def beer-xml-standard-units
+ "The standard units for each measurement type in BeerXML."
+ {options/alcohol-content options/abv
+ options/bitterness options/ibu
+ options/carbonation options/volumes-of-co2
+ options/color options/srm
+ options/pressure options/kilopascal
+ options/specific-gravity options/specific-gravity
+ options/temperature options/celsius
+ options/time options/minute
+ options/volume options/liter
+ options/weight options/kilogram})
+
+
+;; TODO: Pluralize strings
+(defn ->displayable-units
+ "Convert a unit then render it to a displayable value."
+ {:added "2.1"
+ :no-doc true}
+ ([measurement-type source-value source-units target-units]
+ (->displayable-units measurement-type source-value source-units target-units default-display-options))
+ ([measurement-type source-value source-units target-units opts]
+ (let [converted-value (units/convert measurement-type source-value source-units target-units)]
+ (units/display measurement-type converted-value target-units opts))))
+
+
+(defn target-unit-error
+ "A function to accumulate error messages in `error-map` if `target-units` is not a valid unit for `conversion-type`"
+ {:added "2.1"
+ :no-doc true
+ :see-also ["systems-of-meaure-error"
+ "precision-error"
+ "suffix-error"]}
+ [error-map conversion-type target-units]
+ (let [allowed-values (case conversion-type
+ :alcohol-content alcohol-content/measurements
+ :bitterness bitterness/measurements
+ :carbonation carbonation/measurements
+ :color color/measurements
+ :pressure pressure/measurements
+ :specific-gravity specific-gravity/measurements
+ :temperature temperature/measurements
+ :time time/measurements
+ :volume volume/measurements
+ :weight weight/measurements)
+ error-msg (str "Invalid target unit for "
+ (name conversion-type)
+ " conversion : `"
+ target-units
+ "`. Allowed values are: "
+ allowed-values)]
+ (assoc error-map :target-units error-msg)))
+
+
+(defn source-unit-error
+ "A function to accumulate error messages in `error-map` if `source-units` is not a valid unit for `conversion-type`.
+
+ Note: This is only used for color conversion at this time.
+ BeerXML prescribes the system of measure for all other units."
+ {:added "2.1"
+ :no-doc true
+ :see-also ["systems-of-meaure-error"
+ "precision-error"
+ "suffix-error"
+ "target-unit-error"]}
+ [error-map conversion-type source-units]
+ (let [allowed-values (case conversion-type
+ :alcohol-content alcohol-content/measurements
+ :bitterness bitterness/measurements
+ :carbonation carbonation/measurements
+ :color color/measurements
+ :pressure pressure/measurements
+ :specific-gravity specific-gravity/measurements
+ :temperature temperature/measurements
+ :time time/measurements
+ :volume volume/measurements
+ :weight weight/measurements)
+ error-msg (str "Invalid source unit for "
+ (name conversion-type)
+ " conversion : `"
+ source-units
+ "`. Allowed values are: "
+ allowed-values)]
+ (assoc error-map :source-units error-msg)))
+
+
+(defn systems-of-meaure-error
+ "A function to accumulate error messages in `error-map` if `system-of-measure` is not valid for `conversion-type`."
+ {:added "2.1"
+ :no-doc true
+ :see-also ["target-unit-error"
+ "precision-error"
+ "suffix-error"]}
+ [error-map conversion-type system-of-measure]
+ (let [error-msg (str "Invalid system of measure for "
+ (name conversion-type)
+ " conversion : "
+ system-of-measure
+ ". Allowed values are:"
+ options/systems-of-measure)]
+ (assoc error-map options/system-of-measure error-msg)))
+
+
+(defn precision-error
+ "A function to accumulate error messages in `error-map` if `precision` is not an integer."
+ {:added "2.1"
+ :no-doc true
+ :see-also ["target-unit-error"
+ "systems-of-meaure-error"
+ "suffix-error"]}
+ [error-map conversion-type precision]
+ (let [error-msg (str "Invalid precision for "
+ (name conversion-type)
+ " conversion : "
+ precision
+ ". Must be an integer.")]
+ (assoc error-map options/precision error-msg)))
+
+
+(defn suffix-error
+ "A function to accumulate error messages in `error-map` if `suffix` is not a valid choice."
+ {:added "2.1"
+ :no-doc true
+ :see-also ["target-unit-error"
+ "systems-of-meaure-error"
+ "precision-error"]}
+ [error-map conversion-type suffix]
+ (let [error-msg (str "Invalid suffix type for "
+ (name conversion-type)
+ " conversion : "
+ suffix
+ ". Allowed values are: "
+ options/supported-suffixes)]
+ (assoc error-map :suffix error-msg)))
+
+
+;; Enricher argument validation functions
+
+(defn valid-unit-for-measurement-type?
+ "A functions that confirms if a given `unit` is valid for a given `measurement-type`.
+ If the `unit` is not valid, a Java Exception or Javascript Error is thrown with information on the invalid options."
+ {:added "2.1"
+ :no-doc false}
+ [measurement-type unit]
+ (case measurement-type
+ :alcohol-content (contains? alcohol-content/measurements unit)
+ :bitterness (contains? bitterness/measurements unit)
+ :carbonation (contains? carbonation/measurements unit)
+ :color (contains? color/measurements unit)
+ :pressure (contains? pressure/measurements unit)
+ :specific-gravity (contains? specific-gravity/measurements unit)
+ :temperature (contains? temperature/measurements unit)
+ :time (contains? time/measurements unit)
+ :volume (contains? volume/measurements unit)
+ :weight (contains? weight/measurements unit)
+ (throw (ex-info "Unsupported unit system"
+ {:measurement-type measurement-type
+ :allowed-values options/measurement-types}))))
+
+
+(defn parse-enrich-displayable-units-opts
+ "A function to parse the options map passed to `->displayable-units`
+ This requires the user to supply valid values for: `target-units`, `system-of-measure`, `precision`, and `suffix`.
+ If any of these are invalid, a Java Exception or Javascript Error is thrown with information on the invalid options."
+ {:added "2.1"
+ :no-doc true
+ :see-also ["enrich-displayable-units"]}
+ [measurement-type
+ {:keys [target-units source-units system-of-measure precision suffix]
+ :as opts}]
+ (let [valid-source? (valid-unit-for-measurement-type? measurement-type source-units)
+ valid-target? (valid-unit-for-measurement-type? measurement-type target-units)
+ valid-system? (contains? options/systems-of-measure system-of-measure)
+ valid-precision? (int? precision)
+ valid-suffix? (contains? options/supported-suffixes suffix)
+ errors (cond-> {}
+ (not valid-target?) (target-unit-error measurement-type target-units)
+ (not valid-source?) (source-unit-error measurement-type source-units)
+ (not valid-system?) (systems-of-meaure-error measurement-type system-of-measure)
+ (not valid-precision?) (precision-error measurement-type precision)
+ (not valid-suffix?) (suffix-error measurement-type suffix))]
+ (if (empty? errors)
+ opts
+ (throw (ex-info "Invalid enrichment options for ->displayable-units: " errors)))))
+
+
+(defn get-default-unit-by-measurement-type-and-system
+ "A function to get the default unit for a given `measurement-type` and `system-of-measure`.
+ If the measurement type is not supported, a Java Exception or Javascript Error is thrown with information on the invalid options."
+ {:added "2.1"
+ :no-doc true
+ :see-also ["enrich-displayable-units"
+ "enrich-displayable-range"]}
+ [measurement-type system-of-measure]
+ (case measurement-type
+ :alcohol-content (get default-alcohol-content-by-system system-of-measure)
+ :bitterness (get default-bitterness-by-system system-of-measure)
+ :carbonation (get default-carbonation-by-system system-of-measure)
+ :color (get default-color-by-system system-of-measure)
+ :pressure (get default-pressure-by-system system-of-measure)
+ :specific-gravity (get default-specific-gravity-by-system system-of-measure)
+ :temperature (get default-temperature-by-system system-of-measure)
+ :time (get default-time-by-system system-of-measure)
+ :volume (get default-volume-by-system system-of-measure)
+ :weight (get default-weight-by-system system-of-measure)
+ (throw (ex-info "Unsupported unit system"
+ {:measurement-type measurement-type
+ :allowed-values options/measurement-types}))))
+
+
+#_{:clj-kondo/ignore [:shadowed-var]}
+
+
+(defn enrich-displayable-units
+ "A function to enrich a `source-data` map with a displayable value for a given `measurement-type`.
+ This function will convert the `source-value` from `source-units` to `target-units` and store the result in `display-key`.
+ If the `source-value` is not present, the `source-data` is returned unmodified.
+ The function will default to the following display options:
+
+ - `system-of-measure` : `:us-customary`
+ - `suffix` : `:short`
+ - `precision` : `3`
+ - `source-units` : The BeerXML default system of measure for the given `measurement-type` (e.g. `:kilogram` for `:weight`)
+
+ Customization of function behavior is handled by the following keys in the `opts` map, and will always take precedence over defaults:
+
+ - `fine-grain-precsion` : The precision to use for this displayable value. Enricher functions control their behavior off of uniquely named keys, so behavior can be customized per field
+ - `fine-grain-suffix` : The suffix to use for this displayable value. Enricher functions control their behavior off of uniquely named keys, so behavior can be customized per field
+ - `fine-grain-target-units` : The target units to use for this displayable value. Enricher functions control their behavior off of uniquely named keys, so behavior can be customized per field"
+ {:added "2.1"
+ :no-doc true}
+ [measurement-type
+ source-data
+ {:keys [display-key fine-grain-precision fine-grain-suffix fine-grain-target-units precision suffix system-of-measure value-key source-units]
+ :or {system-of-measure options/us-customary
+ suffix options/short
+ precision options/default-precision}}]
+ (if-let [source-value (get source-data value-key)]
+ (let [system-of-measure-units (get-default-unit-by-measurement-type-and-system measurement-type system-of-measure)
+ beer-xml-source-units (get beer-xml-standard-units measurement-type)
+ source-units (or source-units beer-xml-source-units)
+ target-units (or fine-grain-target-units system-of-measure-units)
+ precision (or fine-grain-precision precision)
+ suffix (or fine-grain-suffix suffix)
+ opts (parse-enrich-displayable-units-opts
+ measurement-type
+ {:target-units target-units
+ :source-units source-units
+ options/system-of-measure system-of-measure
+ options/precision precision
+ options/suffix suffix})]
+ (assoc source-data display-key (->displayable-units measurement-type source-value source-units target-units opts)))
+ source-data))
+
+
+#_{:clj-kondo/ignore [:shadowed-var]}
+
+
+(defn enrich-displayable-range
+ "A function to enrich a `source-data` map with a displayable range for a given `measurement-type`.
+ This function will convert the `low-source-value` and `high-source-value` from `source-units` to `target-units` and store the result in `display-key`.
+ If the `source-value` is not present, the `source-data` is returned unmodified.
+ The function will default to the following display options:
+
+ - `system-of-measure` : `:us-customary`
+ - `suffix` : `:short`
+ - `precision` : `3`
+ - `source-units` : The BeerXML default system of measure for the given `measurement-type` (e.g. `:kilogram` for `:weight`)
+
+ Customization of function behavior is handled by the following keys in the `opts` map, and will always take precedence over defaults:
+
+ - `fine-grain-precsion` : The precision to use for this displayable range. Enricher functions control their behavior off of uniquely named keys, so behavior can be customized per field
+ - `fine-grain-suffix` : The suffix to use for this displayable range. Enricher functions control their behavior off of uniquely named keys, so behavior can be customized per field
+ - `fine-grain-target-units` : The target units to use for this displayable range. Enricher functions control their behavior off of uniquely named keys, so behavior can be customized per field"
+ {:added "2.1"
+ :no-doc true
+ :see-also ["enrich-displayable-units"]}
+ [measurement-type
+ source-data
+ {:keys [low-value-key high-value-key display-key system-of-measure suffix precision fine-grain-target-units fine-grain-precision fine-grain-suffix source-units]
+ :or {system-of-measure options/us-customary
+ suffix options/short
+ precision options/default-precision}}]
+ (let [low-source-value (get source-data low-value-key)
+ high-source-value (get source-data high-value-key)]
+ (if (and low-source-value high-source-value)
+ (let [system-of-measure-units (get-default-unit-by-measurement-type-and-system measurement-type system-of-measure)
+ beer-xml-source-units (get beer-xml-standard-units measurement-type)
+ source-units (or source-units beer-xml-source-units)
+ target-units (or fine-grain-target-units system-of-measure-units)
+ precision (or fine-grain-precision precision)
+ suffix (or fine-grain-suffix suffix)
+ opts (parse-enrich-displayable-units-opts
+ measurement-type
+ {:target-units target-units
+ :source-units source-units
+ options/system-of-measure system-of-measure
+ options/precision precision
+ options/suffix suffix})
+ converted-low-value (units/convert measurement-type low-source-value source-units target-units {options/precision precision})
+ displayable-high-value (->displayable-units measurement-type high-source-value source-units target-units opts)
+ displayable-range (str converted-low-value " - " displayable-high-value)]
+ (assoc source-data display-key displayable-range))
+ source-data)))
diff --git a/src/brewtility/enrich/mash.cljc b/src/brewtility/enrich/mash.cljc
new file mode 100644
index 0000000..7ab2b39
--- /dev/null
+++ b/src/brewtility/enrich/mash.cljc
@@ -0,0 +1,516 @@
+(ns brewtility.enrich.mash
+ "Enricher-pattern functions for [mashes and mash steps](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc) maps"
+ {:added "2.1"
+ :see-also ["brewtility.enrich.equipment"
+ "brewtility.enrich.mash-steps"
+ "brewtility.enrich.fermentables"
+ "brewtility.enrich.miscs"
+ "brewtility.enrich.recipes"
+ "brewtility.enrich.styles"
+ "brewtility.enrich.waters"
+ "brewtility.enrich.yeast"]}
+ (:require [brewtility.enrich.impl :as impl]
+ [brewtility.units.options :as options]))
+
+
+(defn enrich-display-step-temperature
+ "An enricher pattern function to render a human-readable display temperature of a [mash step](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-mash-step` and `enrich-mash-step-wrapper`, this function also supports the following keys:
+ - `:display-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["brewtility.enrich.impl/->displayable-temperature"
+ "enrich-mash-step"
+ "enrich-mash-step-wrapper"
+ "enrich-mash-steps"
+ "enrich-mash-steps-wrapper"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash-step] (enrich-display-step-temperature mash-step {}))
+ ([mash-step {:keys [display-temperature-target-units
+ display-temperature-precision
+ display-temperature-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :step-temp
+ impl/display-key :display-step-temp
+ impl/fine-grain-target-units display-temperature-target-units
+ impl/fine-grain-precision display-temperature-precision
+ impl/fine-grain-suffix display-temperature-suffix})]
+ (impl/enrich-displayable-units options/temperature mash-step options))))
+
+
+(defn enrich-display-infuse-amount
+ "An enricher pattern function to render a human-readable infuse amount of a [mash step](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-mash-step` and `enrich-mash-step-wrapper`, this function also supports the following keys:
+ - `:display-infuse-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-infuse-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-infuse-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["brewtility.string/same?"
+ "enrich-mash-step"
+ "enrich-mash-step-wrapper"
+ "enrich-mash-steps"
+ "enrich-mash-steps-wrapper"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash-step] (enrich-display-infuse-amount mash-step {}))
+ ([mash-step {:keys [display-infuse-amount-target-units
+ display-infuse-amount-precision
+ display-infuse-amount-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :infuse-amount
+ impl/display-key :display-infuse-amt
+ impl/fine-grain-target-units display-infuse-amount-target-units
+ impl/fine-grain-precision display-infuse-amount-precision
+ impl/fine-grain-suffix display-infuse-amount-suffix})]
+ (impl/enrich-displayable-units options/volume mash-step options))))
+
+
+(defn enrich-mash-step
+ "An enricher pattern function to derive as many values from an [mash-step record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-step-temperature]]
+ - `:display-temperature-target-units`: The unit to convert the temperature into. Supersedes `:system-of-measure`.
+ - `:display-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-temperature-suffix`: The suffix type to append to the temperature. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:display-infuse-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-infuse-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-infuse-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-step-temperature"
+ "enrich-display-infuse-amount"
+ "enrich-mash-step-wrapper"
+ "enrich-mash-steps"
+ "enrich-mash-steps-wrapper"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash-step] (enrich-mash-step mash-step {}))
+ ([mash-step opts]
+ (-> mash-step
+ (enrich-display-step-temperature opts)
+ (enrich-display-infuse-amount opts))))
+
+
+(defn enrich-mash-step-wrapper
+ "An enricher pattern function to derive as many values from an [mash-step wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-step-temperature]]
+ - `:display-temperature-target-units`: The unit to convert the temperature into. Supersedes `:system-of-measure`.
+ - `:display-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-temperature-suffix`: The suffix type to append to the temperature. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:display-infuse-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-infuse-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-infuse-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-step-temperature"
+ "enrich-display-infuse-amount"
+ "enrich-mash-step"
+ "enrich-mash-steps"
+ "enrich-mash-steps-wrapper"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash-step] (enrich-mash-step-wrapper mash-step {}))
+ ([mash-step opts]
+ (update mash-step :mash-step enrich-mash-step opts)))
+
+
+(defn enrich-mash-steps
+ "An enricher pattern function to derive as many values from a collection of [mash-step wrapper records](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-step-temperature]]
+ - `:display-temperature-target-units`: The unit to convert the temperature into. Supersedes `:system-of-measure`.
+ - `:display-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-temperature-suffix`: The suffix type to append to the temperature. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:display-infuse-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-infuse-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-infuse-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-step-temperature"
+ "enrich-display-infuse-amount"
+ "enrich-mash-step"
+ "enrich-mash-step-wrapper"
+ "enrich-mash-steps-wrapper"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash-steps] (enrich-mash-steps mash-steps {}))
+ ([mash-steps opts]
+ (map #(enrich-mash-step-wrapper % opts) mash-steps)))
+
+
+(defn enrich-mash-steps-wrapper
+ "An enricher pattern function to derive as many values from a collection of [mash-steps wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-step-temperature]]
+ - `:display-temperature-target-units`: The unit to convert the temperature into. Supersedes `:system-of-measure`.
+ - `:display-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-temperature-suffix`: The suffix type to append to the temperature. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:display-infuse-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-infuse-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-infuse-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-step-temperature"
+ "enrich-display-infuse-amount"
+ "enrich-mash-step"
+ "enrich-mash-step-wrapper"
+ "enrich-mash-steps"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash] (enrich-mash-steps-wrapper mash {}))
+ ([mash opts]
+ (update mash :mash-steps enrich-mash-steps opts)))
+
+
+(defn enrich-display-grain-temperature
+ "An enricher pattern function to render a human-readable temperature of the grain temperature during a [mash](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-mash-step` and `enrich-mash-step-wrapper`, this function also supports the following keys:
+ - `:display-grain-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-grain-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-grain-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["brewtility.enrich.impl/->displayable-temperature"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash] (enrich-display-grain-temperature mash {}))
+ ([mash {:keys [display-grain-temperature-target-units
+ display-grain-temperature-precision
+ display-grain-temperature-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :grain-temp
+ impl/display-key :display-grain-temp
+ impl/fine-grain-target-units display-grain-temperature-target-units
+ impl/fine-grain-precision display-grain-temperature-precision
+ impl/fine-grain-suffix display-grain-temperature-suffix})]
+ (impl/enrich-displayable-units options/temperature mash options))))
+
+
+(defn enrich-display-tun-temperature
+ "An enricher pattern function to render a human-readable temperature of the tun temperature during a [mash](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-tuned selections within the context of `enrich-mash-step` and `enrich-mash-step-wrapper`, this function also supports the following keys:
+ - `:display-tun-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-tun-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-tun-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["brewtility.enrich.impl/->displayable-temperature"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash] (enrich-display-tun-temperature mash {}))
+ ([mash {:keys [display-tun-temperature-target-units
+ display-tun-temperature-precision
+ display-tun-temperature-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :tun-temp
+ impl/display-key :display-tun-temp
+ impl/fine-grain-target-units display-tun-temperature-target-units
+ impl/fine-grain-precision display-tun-temperature-precision
+ impl/fine-grain-suffix display-tun-temperature-suffix})]
+ (impl/enrich-displayable-units options/temperature mash options))))
+
+
+(defn enrich-display-sparge-temperature
+ "An enricher pattern function to render a human-readable temperature of the sparge temperature during a [mash](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-spargeed selections within the context of `enrich-mash-step` and `enrich-mash-step-wrapper`, this function also supports the following keys:
+ - `:display-sparge-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-sparge-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-sparge-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["brewtility.enrich.impl/->displayable-temperature"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash] (enrich-display-sparge-temperature mash {}))
+ ([mash {:keys [display-sparge-temperature-target-units
+ display-sparge-temperature-precision
+ display-sparge-temperature-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :sparge-temp
+ impl/display-key :display-sparge-temp
+ impl/fine-grain-target-units display-sparge-temperature-target-units
+ impl/fine-grain-precision display-sparge-temperature-precision
+ impl/fine-grain-suffix display-sparge-temperature-suffix})]
+ (impl/enrich-displayable-units options/temperature mash options))))
+
+
+(defn enrich-display-tun-weight
+ "An enricher pattern function to render a human-readable weight of the tun weight during a [mash](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-tuned selections within the context of `enrich-mash-step` and `enrich-mash-step-wrapper`, this function also supports the following keys:
+ - `:display-tun-weight-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-tun-weight-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-tun-weight-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["brewtility.enrich.impl/->displayable-weight"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash] (enrich-display-tun-weight mash {}))
+ ([mash {:keys [display-tun-weight-target-units
+ display-tun-weight-precision
+ display-tun-weight-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :tun-weight
+ impl/display-key :display-tun-weight
+ impl/fine-grain-target-units display-tun-weight-target-units
+ impl/fine-grain-precision display-tun-weight-precision
+ impl/fine-grain-suffix display-tun-weight-suffix})]
+ (impl/enrich-displayable-units options/weight mash options))))
+
+
+(defn enrich-mash
+ "An enricher pattern function to derive as many values from an [mash record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-step-temperature]]
+ - `:display-temperature-target-units`: The unit to convert the temperature into. Supersedes `:system-of-measure`.
+ - `:display-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-temperature-suffix`: The suffix type to append to the temperature. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:display-infuse-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-infuse-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-infuse-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-grain-temperature]]
+ - `:display-grain-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-grain-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-grain-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-tun-temperature]]
+ - `:display-tun-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-tun-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-tun-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-sparge-temperature]]
+ - `:display-sparge-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-sparge-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-sparge-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`
+ - [[enrich-display-tun-weight]]
+ - `:display-tun-weight-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-tun-weight-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-tun-weight-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-step-temperature"
+ "enrich-display-infuse-amount"
+ "enrich-display-grain-temperature"
+ "enrich-display-tun-temperature"
+ "enrich-display-sparge-temperature"
+ "enrich-display-tun-weight"
+ "enrich-mash-step-wrapper"
+ "enrich-mash-steps"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash] (enrich-mash mash {}))
+ ([mash opts]
+ (-> mash
+ (enrich-mash-steps-wrapper opts)
+ (enrich-display-grain-temperature opts)
+ (enrich-display-tun-temperature opts)
+ (enrich-display-sparge-temperature opts)
+ (enrich-display-tun-weight opts))))
+
+
+(defn enrich-mash-wrapper
+ "An enricher pattern function to derive as many values from an [mash wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/mash.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-step-temperature]]
+ - `:display-temperature-target-units`: The unit to convert the temperature into. Supersedes `:system-of-measure`.
+ - `:display-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-temperature-suffix`: The suffix type to append to the temperature. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:display-infuse-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-infuse-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-infuse-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-grain-temperature]]
+ - `:display-grain-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-grain-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-grain-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-tun-temperature]]
+ - `:display-tun-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-tun-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-tun-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-sparge-temperature]]
+ - `:display-sparge-temperature-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-sparge-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-sparge-temperature-suffix`: The suffix type to append to the amount. Supersedes `:suffix`
+ - [[enrich-display-tun-weight]]
+ - `:display-tun-weight-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:display-tun-weight-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:display-tun-weight-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-step-temperature"
+ "enrich-display-infuse-amount"
+ "enrich-display-grain-temperature"
+ "enrich-display-tun-temperature"
+ "enrich-display-sparge-temperature"
+ "enrich-display-tun-weight"
+ "enrich-mash-step-wrapper"
+ "enrich-mash-steps"
+ "enrich-mash"
+ "enrich-mash-wrapper"]}
+ ([mash] (enrich-mash-wrapper mash {}))
+ ([mash opts]
+ (update mash :mash enrich-mash opts)))
diff --git a/src/brewtility/enrich/miscs.cljc b/src/brewtility/enrich/miscs.cljc
new file mode 100644
index 0000000..64490b2
--- /dev/null
+++ b/src/brewtility/enrich/miscs.cljc
@@ -0,0 +1,260 @@
+(ns brewtility.enrich.miscs
+ "Enricher-pattern functions for [miscs](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/miscs.cljc) maps"
+ {:added "2.1"
+ :see-also ["brewtility.enrich.equipment"
+ "brewtility.enrich.fermentables"
+ "brewtility.enrich.hops"
+ "brewtility.enrich.mash"
+ "brewtility.enrich.recipes"
+ "brewtility.enrich.styles"
+ "brewtility.enrich.waters"
+ "brewtility.enrich.yeast"]}
+ (:require [brewtility.enrich.impl :as impl]
+ [brewtility.units.options :as options]))
+
+
+(defn enrich-amount-is-weight
+ "An enricher pattern function to determine if a [misc](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/miscs.cljc) should be measured by weight/volume.
+ When this feild is not present, it is assumed to be false."
+ {:added "2.1"
+ :see-also ["enrich-misc"
+ "enrich-misc-wrapper"
+ "enrich-miscs"
+ "enrich-miscs-wrapper"]}
+ ([misc] (enrich-amount-is-weight misc {}))
+ ([misc _] ; Used to maintain signature parity with enricher pattern functions
+ (if (contains? misc :amount-is-weight)
+ misc
+ (assoc misc :amount-is-weight false))))
+
+
+(defn enrich-display-time
+ "An enricher pattern function to render a human-readable display time of a [misc](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/miscs.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the time into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the time Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-misc` and `enrich-misc-wrapper`, this function also supports the following keys:
+ - `:misc-time-target-units`: The unit to convert the time into. Supersedes `:system-of-measure`.
+ - `:misc-time-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-time-suffix`: The suffix type to append to the time. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-misc"
+ "enrich-misc-wrapper"
+ "enrich-miscs"
+ "enrich-miscs-wrapper"]}
+ ([misc] (enrich-display-time misc {}))
+ ([misc {:keys [misc-time-target-units
+ misc-time-precision
+ misc-time-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :time
+ impl/display-key :display-time
+ impl/fine-grain-target-units misc-time-target-units
+ impl/fine-grain-precision misc-time-precision
+ impl/fine-grain-suffix misc-time-suffix})]
+ (impl/enrich-displayable-units options/time misc options))))
+
+
+(defn enrich-display-amount
+ "An enricher pattern function to render a human-readable display amount of a [misc](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/miscs.cljc) is in a given system.
+ If the `amount-is-weight` key evaluates truthy, the `amount` will be treated as a weight in kilograms.
+ Otherwise, it will be treated as a volume in liters.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-misc` and `enrich-misc-wrapper`, this function also supports the following keys:
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-misc"
+ "enrich-misc-wrapper"
+ "enrich-miscs"
+ "enrich-miscs-wrapper"]}
+ ([misc] (enrich-display-amount misc {}))
+ ([misc {:keys [misc-amount-target-units
+ misc-amount-precision
+ misc-amount-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :amount
+ impl/display-key :display-amount
+ impl/fine-grain-target-units misc-amount-target-units
+ impl/fine-grain-precision misc-amount-precision
+ impl/fine-grain-suffix misc-amount-suffix})]
+ (if (:amount-is-weight misc)
+ (impl/enrich-displayable-units options/weight misc options)
+ (impl/enrich-displayable-units options/volume misc options)))))
+
+
+(defn enrich-misc
+ "An enricher pattern function to derive as many values from a [misc record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/miscs.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-display-time"
+ "enrich-amount-is-weight"
+ "enrich-misc-wrapper"
+ "enrich-miscs"
+ "enrich-miscs-wrapper"]}
+ ([misc] (enrich-misc misc {}))
+ ([misc opts]
+ (-> misc
+ (enrich-amount-is-weight opts)
+ (enrich-display-amount opts)
+ (enrich-display-time opts))))
+
+
+(defn enrich-misc-wrapper
+ "An enricher pattern function to derive as many values from an [misc-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/miscs.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-display-time"
+ "enrich-amount-is-weight"
+ "enrich-misc"
+ "enrich-miscs"
+ "enrich-miscs-wrapper"]}
+ ([misc] (enrich-misc-wrapper misc {}))
+ ([misc opts]
+ (update misc :misc enrich-misc opts)))
+
+
+(defn enrich-miscs
+ "An enricher pattern function to derive as many values from an [miscs record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/miscs.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-display-time"
+ "enrich-amount-is-weight"
+ "enrich-misc-wrapper"
+ "enrich-misc"
+ "enrich-miscs-wrapper"]}
+ ([miscs] (enrich-miscs miscs {}))
+ ([miscs opts]
+ (map #(enrich-misc-wrapper % opts) miscs)))
+
+
+(defn enrich-miscs-wrapper
+ "An enricher pattern function to derive as many values from an [miscs-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/miscs.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-time]]
+ - `:misc-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:misc-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:misc-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-display-time"
+ "enrich-amount-is-weight"
+ "enrich-misc-wrapper"
+ "enrich-miscs"
+ "enrich-misc"]}
+ ([miscs] (enrich-miscs-wrapper miscs {}))
+ ([miscs opts]
+ (update miscs :miscs enrich-miscs opts)))
+
diff --git a/src/brewtility/enrich/recipes.cljc b/src/brewtility/enrich/recipes.cljc
new file mode 100644
index 0000000..cfd921c
--- /dev/null
+++ b/src/brewtility/enrich/recipes.cljc
@@ -0,0 +1,13 @@
+(ns brewtility.enrich.recipes
+ "Enricher-pattern functions for [recipes](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/recipes.cljc) maps"
+ {:added "2.1"
+ :see-also ["brewtility.enrich.equipment"
+ "brewtility.enrich.fermentables"
+ "brewtility.enrich.hops"
+ "brewtility.enrich.mash"
+ "brewtility.enrich.miscs"
+ "brewtility.enrich.styles"
+ "brewtility.enrich.waters"
+ "brewtility.enrich.yeast"]}
+ (:require [brewtility.enrich.impl :as impl]))
+
diff --git a/src/brewtility/enrich/styles.cljc b/src/brewtility/enrich/styles.cljc
new file mode 100644
index 0000000..a3e364b
--- /dev/null
+++ b/src/brewtility/enrich/styles.cljc
@@ -0,0 +1,328 @@
+(ns brewtility.enrich.styles
+ "Enricher-pattern functions for [styles](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/styles.cljc) maps"
+ {:added "2.1"
+ :see-also ["brewtility.enrich.equipment"
+ "brewtility.enrich.fermentables"
+ "brewtility.enrich.hops"
+ "brewtility.enrich.mash"
+ "brewtility.enrich.miscs"
+ "brewtility.enrich.recipes"
+ "brewtility.enrich.waters"
+ "brewtility.enrich.yeast"]}
+ (:require [brewtility.enrich.impl :as impl]
+ [brewtility.units.options :as options]))
+
+
+(defn enrich-display-og-min
+ "An enricher pattern function to render a human-readable display minimum original gravity of a [style](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/style.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the minimum gravity into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the minimum gravity Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-style` and `enrich-style-wrapper`, this function also supports the following keys:
+ - `:style-display-og-min-target-units`: The unit to convert the minimum gravity into. Supersedes `:system-of-measure`.
+ - `:style-display-og-min-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:style-display-og-min-suffix`: The suffix type to append to the minimum gravity. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-style"
+ "enrich-style-wrapper"
+ "enrich-styles"
+ "enrich-styles-wrapper"]}
+ ([style] (enrich-display-og-min style {}))
+ ([style {:keys [style-display-og-min-target-units
+ style-display-og-min-precision
+ style-display-og-min-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :og-min
+ impl/display-key :display-og-min
+ impl/fine-grain-target-units style-display-og-min-target-units
+ impl/fine-grain-precision style-display-og-min-precision
+ impl/fine-grain-suffix style-display-og-min-suffix})]
+ (impl/enrich-displayable-units options/specific-gravity style options))))
+
+
+(defn enrich-display-og-max
+ "An enricher pattern function to render a human-readable display maximum original gravity of a [style](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/style.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the maximum gravity into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the maximum gravity Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-style` and `enrich-style-wrapper`, this function also supports the following keys:
+ - `:style-display-og-max-target-units`: The unit to convert the maximum gravity into. Supersedes `:system-of-measure`.
+ - `:style-display-og-max-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:style-display-og-max-suffix`: The suffix type to append to the maximum gravity. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-style"
+ "enrich-style-wrapper"
+ "enrich-styles"
+ "enrich-styles-wrapper"]}
+ ([style] (enrich-display-og-max style {}))
+ ([style {:keys [style-display-og-max-target-units
+ style-display-og-max-precision
+ style-display-og-max-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :og-max
+ impl/display-key :display-og-max
+ impl/fine-grain-target-units style-display-og-max-target-units
+ impl/fine-grain-precision style-display-og-max-precision
+ impl/fine-grain-suffix style-display-og-max-suffix})]
+ (impl/enrich-displayable-units options/specific-gravity style options))))
+
+
+(defn enrich-display-fg-min
+ "An enricher pattern function to render a human-readable display minimum final gravity of a [style](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/style.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+- `:system-of-measure`: The unit system of measure to convert the minimum gravity into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the minimum gravity Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-style` and `enrich-style-wrapper`, this function also supports the following keys:
+ - `:style-display-fg-min-target-units`: The unit to convert the minimum gravity into. Supersedes `:system-of-measure`.
+ - `:style-display-fg-min-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:style-display-fg-min-suffix`: The suffix type to append to the minimum gravity. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-style"
+ "enrich-style-wrapper"
+ "enrich-styles"
+ "enrich-styles-wrapper"]}
+ ([style] (enrich-display-fg-min style {}))
+ ([style {:keys [style-display-fg-min-target-units
+ style-display-fg-min-precision
+ style-display-fg-min-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :fg-min
+ impl/display-key :display-fg-min
+ impl/fine-grain-target-units style-display-fg-min-target-units
+ impl/fine-grain-precision style-display-fg-min-precision
+ impl/fine-grain-suffix style-display-fg-min-suffix})]
+ (impl/enrich-displayable-units options/specific-gravity style options))))
+
+
+(defn enrich-display-fg-max
+ "An enricher pattern function to render a human-readable display maximum final gravity of a [style](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/style.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+- `:system-of-measure`: The unit system of measure to convert the maximum gravity into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the maximum gravity Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-style` and `enrich-style-wrapper`, this function also supports the following keys:
+ - `:style-display-fg-max-target-units`: The unit to convert the maximum gravity into. Supersedes `:system-of-measure`.
+ - `:style-display-fg-max-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:style-display-fg-max-suffix`: The suffix type to append to the maximum gravity. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-style"
+ "enrich-style-wrapper"
+ "enrich-styles"
+ "enrich-styles-wrapper"]}
+ ([style] (enrich-display-fg-max style {}))
+ ([style {:keys [style-display-fg-max-target-units
+ style-display-fg-max-precision
+ style-display-fg-max-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :fg-max
+ impl/display-key :display-fg-max
+ impl/fine-grain-target-units style-display-fg-max-target-units
+ impl/fine-grain-precision style-display-fg-max-precision
+ impl/fine-grain-suffix style-display-fg-max-suffix})]
+ (impl/enrich-displayable-units options/specific-gravity style options))))
+
+
+(defn enrich-display-color-min
+ "An enricher pattern function to render a human-readable display minimum color of a [style](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/style.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:color-system` - The color system to use for the conversion. Default is `:lovibond` for type `:grain`, and `:srm` otherwise. Acceptable values are:
+ - `:lovibond` - Use the [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour) system.
+ - `:srm` - Use the [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method) system.
+ - `:ebc` - Use the [European Brewing Convention](https://www.lovibond.com/en/PC/Colour-Measurement/Colour-Scales-Standards/EBC-European-Brewing-Convention) system.
+ - `:rgba` - USe the [RGBa](https://www.w3schools.com/cssref/func_rgba.asp) color system, commonly used in CSS.
+
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the minimum color Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-style` and `enrich-style-wrapper`, this function also supports the following keys:
+ - `:style-display-color-min-target-units`: The unit to convert the minimum color into. Supersedes `:system-of-measure`.
+ - `:style-display-color-min-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:style-display-color-min-suffix`: The suffix type to append to the minimum color. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-style"
+ "enrich-style-wrapper"
+ "enrich-styles"
+ "enrich-styles-wrapper"]}
+ ([style] (enrich-display-color-min style {}))
+ ([style {:keys [color-system
+ style-display-color-min-target-units
+ style-display-color-min-precision
+ style-display-color-min-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :color-min
+ impl/display-key :display-color-min
+ impl/fine-grain-target-units (or style-display-color-min-target-units color-system)
+ impl/fine-grain-precision style-display-color-min-precision
+ impl/fine-grain-suffix style-display-color-min-suffix})]
+ (impl/enrich-displayable-units options/color style options))))
+
+
+(defn enrich-display-color-max
+ "An enricher pattern function to render a human-readable display maximum color of a [style](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/style.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:color-system` - The color system to use for the conversion. Default is `:lovibond` for type `:grain`, and `:srm` otherwise. Acceptable values are:
+ - `:lovibond` - Use the [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour) system.
+ - `:srm` - Use the [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method) system.
+ - `:ebc` - Use the [European Brewing Convention](https://www.lovibond.com/en/PC/Colour-Measurement/Colour-Scales-Standards/EBC-European-Brewing-Convention) system.
+ - `:rgba` - USe the [RGBa](https://www.w3schools.com/cssref/func_rgba.asp) color system, commonly used in CSS.
+
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the maximum color Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-style` and `enrich-style-wrapper`, this function also supports the following keys:
+ - `:style-display-color-max-target-units`: The unit to convert the maximum color into. Supersedes `:system-of-measure`.
+ - `:style-display-color-max-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:style-display-color-max-suffix`: The suffix type to append to the maximum color. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-style"
+ "enrich-style-wrapper"
+ "enrich-styles"
+ "enrich-styles-wrapper"]}
+ ([style] (enrich-display-color-max style {}))
+ ([style {:keys [color-system
+ style-display-color-max-target-units
+ style-display-color-max-precision
+ style-display-color-max-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :color-max
+ impl/display-key :display-color-max
+ impl/fine-grain-target-units (or style-display-color-max-target-units color-system)
+ impl/fine-grain-precision style-display-color-max-precision
+ impl/fine-grain-suffix style-display-color-max-suffix})]
+ (impl/enrich-displayable-units options/color style options))))
+
+
+(defn enrich-og-range
+ "An enricher pattern function to render a human-readable display original gravity ranges for a [style](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/style.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the gravity range into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the gravity range Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-style` and `enrich-style-wrapper`, this function also supports the following keys:
+ - `:style-display-og-range-target-units`: The unit to convert the gravity range into. Supersedes `:system-of-measure`.
+ - `:style-display-og-range-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:style-display-og-range-suffix`: The suffix type to append to the gravity range. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-style"
+ "enrich-style-wrapper"
+ "enrich-styles"
+ "enrich-styles-wrapper"]}
+ ([style] (enrich-og-range style {}))
+ ([style {:keys [style-display-og-range-target-units
+ style-display-og-range-precision
+ style-display-og-range-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/low-value-key :og-min
+ impl/high-value-key :og-max
+ impl/display-key :og-range
+ impl/fine-grain-target-units style-display-og-range-target-units
+ impl/fine-grain-precision style-display-og-range-precision
+ impl/fine-grain-suffix style-display-og-range-suffix})]
+ (impl/enrich-displayable-range options/specific-gravity style options))))
+
+
+(defn enrich-fg-range
+ "An enricher pattern function to render a human-readable display final gravity ranges for a [style](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/style.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the gravity range into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the gravity range Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-style` and `enrich-style-wrapper`, this function also supports the following keys:
+ - `:style-display-fg-range-target-units`: The unit to convert the gravity range into. Supersedes `:system-of-measure`.
+ - `:style-display-fg-range-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:style-display-fg-range-suffix`: The suffix type to append to the gravity range. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-style"
+ "enrich-style-wrapper"
+ "enrich-styles"
+ "enrich-styles-wrapper"]}
+ ([style] (enrich-fg-range style {}))
+ ([style {:keys [style-display-fg-range-target-units
+ style-display-fg-range-precision
+ style-display-fg-range-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/low-value-key :fg-min
+ impl/high-value-key :fg-max
+ impl/display-key :fg-range
+ impl/fine-grain-target-units style-display-fg-range-target-units
+ impl/fine-grain-precision style-display-fg-range-precision
+ impl/fine-grain-suffix style-display-fg-range-suffix})]
+ (impl/enrich-displayable-range options/specific-gravity style options))))
+
+
+;; NOTE CARB AND ABV MIN/MAXES ARE OPTIONAL
diff --git a/src/brewtility/enrich/waters.cljc b/src/brewtility/enrich/waters.cljc
new file mode 100644
index 0000000..5cd1734
--- /dev/null
+++ b/src/brewtility/enrich/waters.cljc
@@ -0,0 +1,177 @@
+(ns brewtility.enrich.waters
+ "Enricher-pattern functions for [waters](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/waters.cljc) maps"
+ {:added "2.1"
+ :see-also ["brewtility.enrich.equipment"
+ "brewtility.enrich.fermentables"
+ "brewtility.enrich.hops"
+ "brewtility.enrich.mash"
+ "brewtility.enrich.miscs"
+ "brewtility.enrich.recipes"
+ "brewtility.enrich.styles"
+ "brewtility.enrich.yeast"]}
+ (:require [brewtility.enrich.impl :as impl]
+ [brewtility.units.options :as options]))
+
+
+(defn enrich-display-amount
+ "An enricher pattern function to render a human-readable display amount of a [water](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/waters.cljc) is in a given system.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-water` and `enrich-water-wrapper`, this function also supports the following keys:
+ - `:water-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:water-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:water-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-water"
+ "enrich-water-wrapper"
+ "enrich-waters"
+ "enrich-waters-wrapper"]}
+ ([water] (enrich-display-amount water {}))
+ ([water {:keys [water-amount-target-units
+ water-amount-precision
+ water-amount-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :amount
+ impl/display-key :display-amount
+ impl/fine-grain-target-units water-amount-target-units
+ impl/fine-grain-precision water-amount-precision
+ impl/fine-grain-suffix water-amount-suffix})]
+ (impl/enrich-displayable-units options/volume water options))))
+
+
+(defn enrich-water
+ "An enricher pattern function to derive as many values from an [water record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/waters.cljc).
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:water-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:water-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:water-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-water-wrapper"
+ "enrich-waters"
+ "enrich-waters-wrapper"]}
+ ([water] (enrich-water water {}))
+ ([water opts]
+ (-> water
+ (enrich-display-amount opts))))
+
+
+(defn enrich-water-wrapper
+ "An enricher pattern function to derive as many values from an [water record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/waters.cljc) as possible.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:water-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:water-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:water-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-water"
+ "enrich-waters"
+ "enrich-waters-wrapper"]}
+ ([water] (enrich-water-wrapper water {}))
+ ([water opts]
+ (update water :water enrich-water opts)))
+
+
+(defn enrich-waters
+ "An enricher pattern function to derive as many values from a collection of [water records](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/waters.cljc) as possible.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:water-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:water-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:water-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-water"
+ "enrich-water-wrapper"
+ "enrich-waters-wrapper"]}
+ ([waters] (enrich-waters waters {}))
+ ([waters opts]
+ (map #(enrich-water % opts) waters)))
+
+
+(defn enrich-waters-wrapper
+ "An enricher pattern function to derive as many values from a collection of [water records](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/waters.cljc) as possible.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+ - [[enrich-display-amount]]
+ - `:water-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:water-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:water-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-display-amount"
+ "enrich-water"
+ "enrich-water-wrapper"
+ "enrich-waters"
+ "enrich-waters-wrapper"]}
+ ([waters] (enrich-waters waters {}))
+ ([waters opts]
+ (update waters :waters enrich-waters opts)))
diff --git a/src/brewtility/enrich/yeasts.cljc b/src/brewtility/enrich/yeasts.cljc
new file mode 100644
index 0000000..f1bddb7
--- /dev/null
+++ b/src/brewtility/enrich/yeasts.cljc
@@ -0,0 +1,328 @@
+(ns brewtility.enrich.yeasts
+ "Enricher-pattern functions for [yeasts](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) maps"
+ {:added "2.1"
+ :see-also ["brewtility.enrich.equipment"
+ "brewtility.enrich.fermentables"
+ "brewtility.enrich.hops"
+ "brewtility.enrich.mash"
+ "brewtility.enrich.yeasts"
+ "brewtility.enrich.recipes"
+ "brewtility.enrich.styles"
+ "brewtility.enrich.waters"]}
+ (:require [brewtility.enrich.impl :as impl]
+ [brewtility.units.options :as options]))
+
+
+(defn enrich-amount-is-weight
+ "An enricher pattern function to determine if a [yeast](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) should be measured by weight/volume.
+ When this feild is not present, it is assumed to be false."
+ {:added "2.1"
+ :see-also ["enrich-yeast"
+ "enrich-yeast-wrapper"
+ "enrich-yeasts"
+ "enrich-yeasts-wrapper"]}
+ ([yeast] (enrich-amount-is-weight yeast {}))
+ ([yeast _] ; Used to maintain signature parity with enricher pattern functions
+ (if (contains? yeast :amount-is-weight)
+ yeast
+ (assoc yeast :amount-is-weight false))))
+
+
+(defn enrich-display-amount
+ "An enricher pattern function to render a human-readable display amount of a [yeast](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) is in a given system.
+ If the `amount-is-weight` key evaluates truthy, the `amount` will be treated as a weight in kilograms.
+ Otherwise, it will be treated as a volume in liters.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the amount Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-yeast` and `enrich-yeast-wrapper`, this function also supports the following keys:
+ - `:yeast-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `:yeast-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-yeast"
+ "enrich-yeast-wrapper"
+ "enrich-yeasts"
+ "enrich-yeasts-wrapper"]}
+ ([yeast] (enrich-display-amount yeast {}))
+ ([yeast {:keys [yeast-amount-target-units
+ yeast-amount-precision
+ yeast-amount-suffix]
+ :as opts}]
+ (let [options (merge opts {impl/value-key :amount
+ impl/display-key :display-amount
+ impl/fine-grain-target-units yeast-amount-target-units
+ impl/fine-grain-precision yeast-amount-precision
+ impl/fine-grain-suffix yeast-amount-suffix})]
+ (if (:amount-is-weight yeast)
+ (impl/enrich-displayable-units options/weight yeast options)
+ (impl/enrich-displayable-units options/volume yeast options)))))
+
+
+(defn enrich-display-min-temperature
+ "An enricher pattern function to render a human-readable display minimum-viable fermentation temperature of a [yeast](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) is in a given system.
+ If the `min-temperature` key is not present, the map will not be changed.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the min-temperature into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the min-temperature Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-yeast` and `enrich-yeast-wrapper`, this function also supports the following keys:
+ - `:yeast-min-temperature-target-units`: The unit to convert the min-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-min-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-min-temperature-suffix`: The suffix type to append to the min-temperature. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-yeast"
+ "enrich-yeast-wrapper"
+ "enrich-yeasts"
+ "enrich-yeasts-wrapper"]}
+ ([yeast] (enrich-display-min-temperature yeast {}))
+ ([yeast {:keys [yeast-min-temperature-target-units
+ yeast-min-temperature-precision
+ yeast-min-temperature-suffix]
+ :as opts}]
+ (if (:min-temperature yeast)
+ (let [options (merge opts {impl/value-key :min-temperature
+ impl/display-key :disp-min-temp
+ impl/fine-grain-target-units yeast-min-temperature-target-units
+ impl/fine-grain-precision yeast-min-temperature-precision
+ impl/fine-grain-suffix yeast-min-temperature-suffix})]
+ (impl/enrich-displayable-units options/temperature yeast options))
+ yeast)))
+
+
+(defn enrich-display-max-temperature
+ "An enricher pattern function to render a human-readable display maximum-viable fermentation temperature of a [yeast](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) is in a given system.
+ If the `max-temperature` key is not present, the map will not be changed.
+
+ An option map may be passed as an optional second argument to this function to override the default behavior.
+ Supported keys include:
+
+ - `:system-of-measure`: The unit system of measure to convert the max-temperature into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to the max-temperature Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"lb\"` for `\"pounds\"`.
+ - `:full`: The full name of the selected unit. For example, `\"gram\"` for `\"gram\"`.
+
+ To support fine-grained selections within the context of `enrich-yeast` and `enrich-yeast-wrapper`, this function also supports the following keys:
+ - `:yeast-max-temperature-target-units`: The unit to convert the max-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-max-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-max-temperature-suffix`: The suffix type to append to the max-temperature. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-yeast"
+ "enrich-yeast-wrapper"
+ "enrich-yeasts"
+ "enrich-yeasts-wrapper"]}
+ ([yeast] (enrich-display-max-temperature yeast {}))
+ ([yeast {:keys [yeast-max-temperature-target-units
+ yeast-max-temperature-precision
+ yeast-max-temperature-suffix]
+ :as opts}]
+ (if (:max-temperature yeast)
+ (let [options (merge opts {impl/value-key :max-temperature
+ impl/display-key :disp-max-temp
+ impl/fine-grain-target-units yeast-max-temperature-target-units
+ impl/fine-grain-precision yeast-max-temperature-precision
+ impl/fine-grain-suffix yeast-max-temperature-suffix})]
+ (impl/enrich-displayable-units options/temperature yeast options))
+ yeast)))
+
+
+(defn enrich-yeast
+ "An enricher pattern function to derive as many values from a [yeast record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) as possible.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+
+ - [[enrich-display-amount]]
+ - `:yeast-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `yeast-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `yeast-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-min-temperature]]
+ - `:yeast-min-temperature-target-units`: The unit to convert the min-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-min-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-min-temperature-suffix`: The suffix type to append to the min-temperature. Supersedes `:suffix`.
+ - [[enrich-display-max-temperature]]
+ - `:yeast-max-temperature-target-units`: The unit to convert the max-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-max-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-max-temperature-suffix`: The suffix type to append to the max-temperature. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-amount-is-weight"
+ "enrich-display-amount"
+ "enrich-display-min-temperature"
+ "enrich-display-max-temperature"
+ "enrich-yeast-wrapper"
+ "enrich-yeasts"
+ "enrich-yeasts-wrapper"]}
+ ([yeast] (enrich-yeast yeast {}))
+ ([yeast opts]
+ (-> yeast
+ (enrich-amount-is-weight opts)
+ (enrich-display-amount opts)
+ (enrich-display-min-temperature opts)
+ (enrich-display-max-temperature opts))))
+
+
+(defn enrich-yeast-wrapper
+ "An enricher pattern function to derive as many values from a [yeast-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) as possible.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+
+ - [[enrich-display-amount]]
+ - `:yeast-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `yeast-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `yeast-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-min-temperature]]
+ - `:yeast-min-temperature-target-units`: The unit to convert the min-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-min-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-min-temperature-suffix`: The suffix type to append to the min-temperature. Supersedes `:suffix`.
+ - [[enrich-display-max-temperature]]
+ - `:yeast-max-temperature-target-units`: The unit to convert the max-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-max-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-max-temperature-suffix`: The suffix type to append to the max-temperature. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-amount-is-weight"
+ "enrich-display-amount"
+ "enrich-display-min-temperature"
+ "enrich-display-max-temperature"
+ "enrich-yeast-wrapper"
+ "enrich-yeasts"
+ "enrich-yeasts-wrapper"]}
+ ([yeast-wrapper] (enrich-yeast-wrapper yeast-wrapper {}))
+ ([yeast-wrapper opts]
+ (update yeast-wrapper :yeast enrich-yeast opts)))
+
+
+(defn enrich-yeasts
+ "An enricher pattern function to derive as many values from a [yeast-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) as possible.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+
+ - [[enrich-display-amount]]
+ - `:yeast-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `yeast-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `yeast-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-min-temperature]]
+ - `:yeast-min-temperature-target-units`: The unit to convert the min-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-min-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-min-temperature-suffix`: The suffix type to append to the min-temperature. Supersedes `:suffix`.
+ - [[enrich-display-max-temperature]]
+ - `:yeast-max-temperature-target-units`: The unit to convert the max-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-max-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-max-temperature-suffix`: The suffix type to append to the max-temperature. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-amount-is-weight"
+ "enrich-display-amount"
+ "enrich-display-min-temperature"
+ "enrich-display-max-temperature"
+ "enrich-yeast-wrapper"
+ "enrich-yeasts"
+ "enrich-yeasts-wrapper"]}
+ ([yeasts] (enrich-yeasts yeasts {}))
+ ([yeasts opts]
+ (map #(enrich-yeast-wrapper % opts) yeasts)))
+
+
+(defn enrich-yeasts-wrapper
+ "An enricher pattern function to derive as many values from a [yeast-wrapper record](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/yeasts.cljc) as possible.
+
+ An option map may be passed as an optional second argument.
+ The following keys are supported for controlling high-level behavior:
+
+ - `:system-of-measure`: The unit system of measure to convert the amount into. Defaults to `:us`. Acceptable values are:
+ - `:imperial`: The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
+ - `:metric`: The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
+ - `:us`: The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
+ - `:si`: The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
+ - `:precision`: The number of significant decimal places to display. Defaults to 3.
+ - `:suffix`: The suffix type to append to displayable units. Defaults to `:short`. Acceptable values are:
+ - `:short`: A customary abbreviation for the selected unit. For example, `\"°L\"` for `:lovibond`.
+ - `:full`: The full name of the selected unit. For example, `\"° Lovibond\"` for `:lovibond`.
+
+ To support fine-grained control of behavior, this function also supports the following keys inherited from the other field-specific enrichers:
+
+ - [[enrich-display-amount]]
+ - `:yeast-amount-target-units`: The unit to convert the amount into. Supersedes `:system-of-measure`.
+ - `yeast-amount-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `yeast-amount-suffix`: The suffix type to append to the amount. Supersedes `:suffix`.
+ - [[enrich-display-min-temperature]]
+ - `:yeast-min-temperature-target-units`: The unit to convert the min-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-min-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-min-temperature-suffix`: The suffix type to append to the min-temperature. Supersedes `:suffix`.
+ - [[enrich-display-max-temperature]]
+ - `:yeast-max-temperature-target-units`: The unit to convert the max-temperature into. Supersedes `:system-of-measure`.
+ - `:yeast-max-temperature-precision`: The number of significant decimal places to display. Supersedes `:precision`.
+ - `:yeast-max-temperature-suffix`: The suffix type to append to the max-temperature. Supersedes `:suffix`."
+ {:added "2.1"
+ :see-also ["enrich-amount-is-weight"
+ "enrich-display-amount"
+ "enrich-display-min-temperature"
+ "enrich-display-max-temperature"
+ "enrich-yeast-wrapper"
+ "enrich-yeasts"
+ "enrich-yeasts-wrapper"]}
+ ([yeasts-wrapper] (enrich-yeasts-wrapper yeasts-wrapper {}))
+ ([yeasts-wrapper opts]
+ (update yeasts-wrapper :yeasts enrich-yeasts opts)))
diff --git a/src/brewtility/precision.cljc b/src/brewtility/precision.cljc
index 703a48f..55aff62 100644
--- a/src/brewtility/precision.cljc
+++ b/src/brewtility/precision.cljc
@@ -8,14 +8,21 @@
"Determine if `n2` approximates `n1` within `variance` percent."
{:added "1.0"}
[n1 n2 variance]
- (let [upper-bound (* n1 (+ 1.0 variance))
- lower-bound (* n1 (- 1.0 variance))]
- (<= lower-bound n2 upper-bound)))
+ (if (and (number? n1)
+ (number? n2)
+ (number? variance))
+ (let [upper-bound (* n1 (+ 1.0 variance))
+ lower-bound (* n1 (- 1.0 variance))]
+ (<= lower-bound n2 upper-bound))
+ (throw (ex-info "Cannot approximate using non-numeric values" {:n1 n1
+ :n2 n2
+ :variance variance}))))
(defn ->precision
"Given a decimal `x` and the number of decimal places, returns that number rounded to `num-decimals` precision."
- {:added "1.0"}
+ {:added "1.0"
+ :see-also ["->1dp" "->2dp" "->3dp"]}
[^double x ^long num-decimals]
(double
#?(:clj (.setScale (bigdec x) num-decimals RoundingMode/HALF_UP)
diff --git a/src/brewtility/predicates/equipment.cljc b/src/brewtility/predicates/equipment.cljc
index 2e9a603..36559c8 100644
--- a/src/brewtility/predicates/equipment.cljc
+++ b/src/brewtility/predicates/equipment.cljc
@@ -1,5 +1,5 @@
(ns brewtility.predicates.equipment
- "Predicate functions for [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) maps"
+ "Predicate functions for [equipment](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/equipment.cljc) maps."
{:added "1.5"
:see-also ["brewtility.predicates.fermentables"
"brewtility.predicates.hops"
@@ -16,7 +16,10 @@
In the BeerXML spec, this behavior is implicitly falsey.
Therefore, if the :calc-boil-volume field is not present, this function will explicitly return false."
{:added "1.5"}
- [equipment]
- (if (contains? equipment :calc-boil-volume)
- (:calc-boil-volume equipment)
- false))
+ ([equipment] (calculated-boil-volume? equipment {}))
+ ;; Added to match the arity of the other predicate functions
+
+ ([equipment _opts]
+ (if (contains? equipment :calc-boil-volume)
+ (:calc-boil-volume equipment)
+ false)))
diff --git a/src/brewtility/predicates/fermentables.cljc b/src/brewtility/predicates/fermentables.cljc
index 82ca517..2c4074d 100644
--- a/src/brewtility/predicates/fermentables.cljc
+++ b/src/brewtility/predicates/fermentables.cljc
@@ -19,10 +19,13 @@
Therefore, if the :add-after-boil field is not present, this function will explicitly return false."
{:added "1.5"}
- [fermentable]
- (if (contains? fermentable :add-after-boil)
- (:add-after-boil fermentable)
- false))
+ ([fermentable] (add-after-boil? fermentable {}))
+ ;; Added to match the arity of the other predicate functions
+
+ ([fermentable _opts]
+ (if (contains? fermentable :add-after-boil)
+ (:add-after-boil fermentable)
+ false)))
(defn grain?
diff --git a/src/brewtility/predicates/hops.cljc b/src/brewtility/predicates/hops.cljc
index 50a73be..617ef1a 100644
--- a/src/brewtility/predicates/hops.cljc
+++ b/src/brewtility/predicates/hops.cljc
@@ -148,8 +148,7 @@
"A predicate function to determine if a [hop](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc) was added for both bittering and aroma.
An option map can be passed to this function as an optional second parameter.
Supported keys are:
- - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false.
- - `:coerce` - If the `:type` field should be coerced to a string for comparison. Default is false."
+ - `:uppercase?` - If the string comparison for the `:type` should be cast to UPPERCASE instead of lowercase. Default is false."
{:added "1.5"
:see-also ["aroma-type?"
"bittering?"
@@ -169,8 +168,7 @@
"A predicate function to determine if a [hop](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc) was a compressed pellet.
An option map can be passed to this function as an optional second parameter.
Supported keys are:
- - `:uppercase?` - If the string comparison for the `:form` should be cast to UPPERCASE instead of lowercase. Default is false.
- - `:coerce` - If the `:form` field should be coerced to a string for comparison. Default is false."
+ - `:uppercase?` - If the string comparison for the `:form` should be cast to UPPERCASE instead of lowercase. Default is false."
{:added "1.5"
:see-also ["plug?"
"leaf?"
@@ -185,8 +183,7 @@
"A predicate function to determine if a [hop](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc) was a compressed whole-hop plug.
An option map can be passed to this function as an optional second parameter.
Supported keys are:
- - `:uppercase?` - If the string comparison for the `:form` should be cast to UPPERCASE instead of lowercase. Default is false.
- - `:coerce` - If the `:form` field should be coerced to a string for comparison. Default is false."
+ - `:uppercase?` - If the string comparison for the `:form` should be cast to UPPERCASE instead of lowercase. Default is false."
{:added "1.5"
:see-also ["pellet?"
"leaf?"
@@ -201,8 +198,7 @@
"A predicate function to determine if a [hop](https://github.com/Wall-Brew-Co/common-beer-format/blob/master/src/common_beer_format/hops.cljc) was a whole hop cone.
An option map can be passed to this function as an optional second parameter.
Supported keys are:
- - `:uppercase?` - If the string comparison for the `:form` should be cast to UPPERCASE instead of lowercase. Default is false.
- - `:coerce` - If the `:form` field should be coerced to a string for comparison. Default is false."
+ - `:uppercase?` - If the string comparison for the `:form` should be cast to UPPERCASE instead of lowercase. Default is false."
{:added "1.5"
:see-also ["pellet?"
"plug?"
diff --git a/src/brewtility/predicates/mash.cljc b/src/brewtility/predicates/mash.cljc
index d937eab..2408f21 100644
--- a/src/brewtility/predicates/mash.cljc
+++ b/src/brewtility/predicates/mash.cljc
@@ -18,10 +18,13 @@
In the BeerXML spec, this behavior is implicitly falsey.
Therefore, if the `:equip-adjust` field is not present, this function will return false."
{:added "1.5"}
- [mash]
- (if (contains? mash :equip-adjust)
- (:equip-adjust mash)
- false))
+ ([mash] (adjust-for-equipment? mash {}))
+ ;; Added to match the arity of the other predicate functions
+
+ ([mash _opts]
+ (if (contains? mash :equip-adjust)
+ (:equip-adjust mash)
+ false)))
(defn infusion?
diff --git a/src/brewtility/predicates/options.cljc b/src/brewtility/predicates/options.cljc
new file mode 100644
index 0000000..036c564
--- /dev/null
+++ b/src/brewtility/predicates/options.cljc
@@ -0,0 +1,15 @@
+(ns brewtility.predicates.options
+ "A namespace of static symbolic keywords and values used in the option maps throughout brewtility.
+
+ Implemented as part of the Symbolic Keyword pattern."
+ {:added "2.1"})
+
+
+;; Option keys
+
+(def uppercase?
+ "A keyword used to determine if a string comparison should be cast to UPPERCASE instead of lowercase.
+
+ This option is inherited from the functions in `com.wallbrew.spoon.string`"
+ :uppercase?)
+
diff --git a/src/brewtility/predicates/recipes.cljc b/src/brewtility/predicates/recipes.cljc
index 709ef5d..382b611 100644
--- a/src/brewtility/predicates/recipes.cljc
+++ b/src/brewtility/predicates/recipes.cljc
@@ -18,10 +18,13 @@
In the BeerXML spec, this behavior is implicitly falsey.
Therefore, if the :forced-carbonation field is not present, this function will explicitly return false."
{:added "1.5"}
- [recipe]
- (if (contains? recipe :forced-carbonation)
- (:forced-carbonation recipe)
- false))
+ ([recipe] (forced-carbonation? recipe {}))
+ ;; Added to match the arity of the other predicate functions
+
+ ([recipe _opts]
+ (if (contains? recipe :forced-carbonation)
+ (:forced-carbonation recipe)
+ false)))
(defn extract?
diff --git a/src/brewtility/predicates/waters.cljc b/src/brewtility/predicates/waters.cljc
index 71a5892..da5cb33 100644
--- a/src/brewtility/predicates/waters.cljc
+++ b/src/brewtility/predicates/waters.cljc
@@ -17,9 +17,12 @@
{:added "1.5"
:see-also ["alkaline?"
"neutral?"]}
- [water]
- (let [ph (impl/fetch-or-throw! water :ph "Water `:ph` is required to determine acidity.")]
- (> 7 ph)))
+ ([water] (acidic? water {}))
+ ;; Added to match the arity of the other predicate functions
+
+ ([water _opts]
+ (let [ph (impl/fetch-or-throw! water :ph "Water `:ph` is required to determine acidity.")]
+ (> 7 ph))))
(defn alkaline?
@@ -27,9 +30,12 @@
{:added "1.5"
:see-also ["acidic?"
"neutral?"]}
- [water]
- (let [ph (impl/fetch-or-throw! water :ph "Water `:ph` is required to determine alkalinity.")]
- (< 7 ph)))
+ ([water] (alkaline? water {}))
+ ;; Added to match the arity of the other predicate functions
+
+ ([water _opts]
+ (let [ph (impl/fetch-or-throw! water :ph "Water `:ph` is required to determine alkalinity.")]
+ (< 7 ph))))
(defn neutral?
@@ -37,6 +43,9 @@
{:added "1.5"
:see-also ["acidic?"
"alkaline?"]}
- [water]
- (let [ph (impl/fetch-or-throw! water :ph "Water `:ph` is required to determine ph neutrality.")]
- (== 7 ph)))
+ ([water] (neutral? water {}))
+ ;; Added to match the arity of the other predicate functions
+
+ ([water _opts]
+ (let [ph (impl/fetch-or-throw! water :ph "Water `:ph` is required to determine ph neutrality.")]
+ (== 7 ph))))
diff --git a/src/brewtility/units.cljc b/src/brewtility/units.cljc
index 76b1735..c877693 100644
--- a/src/brewtility/units.cljc
+++ b/src/brewtility/units.cljc
@@ -1,8 +1,10 @@
(ns brewtility.units
"Namespace for converting between different units of measure.
-
+
Currently, brewtility supports the following types of measurements:
-
+
+ - [Bitterness](https://en.wikipedia.org/wiki/Beer_measurement#Bitterness)
+ - [Carbonation](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages)
- [Color](https://en.wikipedia.org/wiki/Beer_measurement#Colour)
- [Pressure](https://en.wikipedia.org/wiki/Pressure)
- [Specific Gravity](https://en.wikipedia.org/wiki/Relative_density)
@@ -10,16 +12,20 @@
- [Time](https://en.wikipedia.org/wiki/Time)
- [Volume](https://en.wikipedia.org/wiki/Volume)
- [Weight](https://en.wikipedia.org/wiki/Mass)
-
+
These types of measurement cover four systems of measure:
-
+
- [The British Imperial System](https://en.wikipedia.org/wiki/Imperial_units)
- [The Metric System](https://en.wikipedia.org/wiki/Metric_system)
- [The International System](https://en.wikipedia.org/wiki/International_System_of_Units)
- [The US Customary Scale](https://en.wikipedia.org/wiki/United_States_customary_units)"
{:added "1.0"
:changed "2.0"}
- (:require [brewtility.units.color :as color]
+ (:require [brewtility.precision :as precision]
+ [brewtility.units.alcohol-content :as alcohol-content]
+ [brewtility.units.bitterness :as bitterness]
+ [brewtility.units.carbonation :as carbonation]
+ [brewtility.units.color :as color]
[brewtility.units.options :as options]
[brewtility.units.pressure :as pressure]
[brewtility.units.specific-gravity :as specific-gravity]
@@ -31,36 +37,50 @@
(defn convert
"Given a `measurement` in `source-units`, convert it to the `target-units` in a given `measurement-type`.
-
+
For example:
-
+
```clj
(convert :weight 1.5 :kg :lb) ;; => 3.31
```
-
+
Supported values for `source-units` and `target-units` are enumerated in each unit system namespace.
- This function will throw an exception if unsupported unit values are passed."
+ This function will throw an exception if unsupported unit values are passed.
+
+ This function accepts an option map as an optional fourth argument. The following options are available:
+ - `precision`: The number of decimal places to round to. Defaults to the precision of the converted value."
{:added "2.0"
- :see-also ["brewtility.units.color/convert"
+ :see-also ["brewtility.units.alcohol-content/convert"
+ "brewtility.units.bitterness/convert"
+ "brewtility.units.carbonation/convert"
+ "brewtility.units.color/convert"
"brewtility.units.pressure/convert"
"brewtility.units.specific-gravity/convert"
"brewtility.units.temperature/convert"
"brewtility.units.time/convert"
"brewtility.units.volume/convert"
"brewtility.units.weight/convert"]}
- [measurement-type measurement source-units target-units]
- (case measurement-type
- :color (color/convert measurement source-units target-units)
- :pressure (pressure/convert measurement source-units target-units)
- :specific-gravity (specific-gravity/convert measurement source-units target-units)
- :temperature (temperature/convert measurement source-units target-units)
- :time (time/convert measurement source-units target-units)
- :volume (volume/convert measurement source-units target-units)
- :weight (weight/convert measurement source-units target-units)
- (throw (ex-info "Unsupported unit system"
- {:measurement-type measurement-type
- :allowed-values options/measurement-types
- :measurement measurement}))))
+ ([measurement-type measurement source-units target-units]
+ (convert measurement-type measurement source-units target-units {}))
+ ([measurement-type measurement source-units target-units {:keys [precision]}]
+ (let [converted-value (case measurement-type
+ :alcohol-content (alcohol-content/convert measurement source-units target-units)
+ :bitterness (bitterness/convert measurement source-units target-units)
+ :carbonation (carbonation/convert measurement source-units target-units)
+ :color (color/convert measurement source-units target-units)
+ :pressure (pressure/convert measurement source-units target-units)
+ :specific-gravity (specific-gravity/convert measurement source-units target-units)
+ :temperature (temperature/convert measurement source-units target-units)
+ :time (time/convert measurement source-units target-units)
+ :volume (volume/convert measurement source-units target-units)
+ :weight (weight/convert measurement source-units target-units)
+ (throw (ex-info "Unsupported unit system"
+ {:measurement-type measurement-type
+ :allowed-values options/measurement-types
+ :measurement measurement})))]
+ (if precision
+ (precision/->precision converted-value precision)
+ converted-value))))
(defn display
@@ -76,7 +96,10 @@
- `:short`: A customary abbreviation for the selected unit. For example, `\"gal\"` for `\" US gallons\"`.
- `:full`: The full name of the selected unit. For example, `\"teaspoon\"` for `\"teaspoon\"`."
{:added "2.0"
- :see-also ["brewtility.units.color/display"
+ :see-also ["brewtility.units.alcohol-content/display"
+ "brewtility.units.bitterness/display"
+ "brewtility.units.carbonation/display"
+ "brewtility.units.color/display"
"brewtility.units.pressure/display"
"brewtility.units.specific-gravity/display"
"brewtility.units.temperature/display"
@@ -90,6 +113,9 @@
(let [options (merge {options/precision options/default-precision
options/suffix options/short} opts)]
(case measurement-type
+ :alcohol-content (alcohol-content/display measurement source-units options)
+ :bitterness (bitterness/display measurement source-units options)
+ :carbonation (carbonation/display measurement source-units options)
:color (color/display measurement source-units options)
:pressure (pressure/display measurement source-units options)
:specific-gravity (specific-gravity/display measurement source-units options)
diff --git a/src/brewtility/units/alcohol_content.cljc b/src/brewtility/units/alcohol_content.cljc
new file mode 100644
index 0000000..b4c73cf
--- /dev/null
+++ b/src/brewtility/units/alcohol_content.cljc
@@ -0,0 +1,85 @@
+(ns brewtility.units.alcohol-content
+ "A namespace for converting between different units for measuring alcohol content.
+
+ In the BeerXML spec, the default unit to measure the alcohol content is ABV (Alcohol by Volume).
+ This namespace converts between that measure and other units.
+
+ Currently, brewtility supports the following types of IBU:
+ - [abv](https://en.wikipedia.org/wiki/Alcohol_by_volume)"
+ {:added "2.1"}
+ (:require [brewtility.precision :as precision]
+ [brewtility.units.options :as options]))
+
+
+(def measurements
+ "The alcohol content measurement systems available across brewtility."
+ #{options/abv})
+
+
+(def measurements->display-name
+ "A map from alcohol content system names to their full and short unit names."
+ {options/abv {options/full "% alcohol by volume"
+ options/short "% abv"}})
+
+
+(def measurement->abv
+ "A map from alcohol content system names to the conversion function to ABV"
+ {options/abv identity})
+
+
+(def abv->measurement
+ "A map from alcohol content system names to the conversion function from ABV."
+ {options/abv identity})
+
+
+(defn convert
+ "Given an `alcohol-content` in `source-measurement`, convert it to the `target-measurement`.
+ Supported values for `source-measurement` and `target-measurement` are enumerated in [[alcohol-content-measurements]].
+ This function will throw an exception if unsupported measurement values are passed."
+ {:added "2.1"}
+ [alcohol-content source-measurement target-measurement]
+ (if (and (contains? measurements source-measurement)
+ (contains? measurements target-measurement)
+ (number? alcohol-content))
+ (if (= source-measurement target-measurement)
+ alcohol-content
+ (let [source->ibu-fn (measurement->abv source-measurement)
+ ibu->target-fn (abv->measurement target-measurement)]
+ (-> alcohol-content source->ibu-fn ibu->target-fn)))
+ (throw (ex-info "Unsupported alcohol content conversion units"
+ {:source-measurement source-measurement
+ :target-measurement target-measurement
+ :allowed-values measurements
+ :alcohol-content alcohol-content}))))
+
+
+(defn display
+ "A function to render a human-readable `alcohol-content` in `source-units`.
+
+ For example,
+ ```clj
+ (display .1 options/abv)
+ ;; => \"10% abv\"
+ ```"
+ {:added "2.1"}
+ ([alcohol-content source-units]
+ (display alcohol-content source-units {}))
+ ([alcohol-content source-units {:keys [precision suffix]
+ :or {precision options/default-precision
+ suffix options/short}}]
+ (if (and (contains? measurements source-units)
+ (number? alcohol-content)
+ (integer? precision)
+ (contains? options/supported-suffixes suffix))
+ (let [display-name (get-in measurements->display-name [source-units suffix])]
+ (-> alcohol-content
+ (* 100.0) ; ABV is a percentage, so multiply by 100
+ (precision/->precision precision)
+ (str display-name)))
+ (throw (ex-info "Unsupported alcohol content display units"
+ {:source-units source-units
+ :allowed-values measurements
+ :alcohol-content alcohol-content
+ :precision precision
+ :suffix suffix
+ :supported-suffixes options/supported-suffixes})))))
diff --git a/src/brewtility/units/bitterness.cljc b/src/brewtility/units/bitterness.cljc
new file mode 100644
index 0000000..beb859d
--- /dev/null
+++ b/src/brewtility/units/bitterness.cljc
@@ -0,0 +1,84 @@
+(ns brewtility.units.bitterness
+ "A namespace for converting between different units of bitterness.
+
+ In the BeerXML spec, IBU is a measure of the bitterness of beer, which is determined by the quantity, type, and timing of hops used in brewing.
+ This namespace converts between that measure and other units.
+
+ Currently, brewtility supports the following types of IBU:
+ - [international-bitterness-units](https://en.wikipedia.org/wiki/International_bitterness_units)"
+ {:added "2.1"}
+ (:require [brewtility.precision :as precision]
+ [brewtility.units.options :as options]))
+
+
+(def measurements
+ "The bitterness measurement systems available across brewtility."
+ #{options/ibu})
+
+
+(def measurements->display-name
+ "A map from IBU system names to their full and short unit names."
+ {options/ibu {options/full "international bitterness units"
+ options/short "ibu"}})
+
+
+(def measurement->ibu
+ "A map from IBU system names to the conversion function to IBU."
+ {options/ibu identity})
+
+
+(def ibu->measurement
+ "A map from IBU system names to the conversion function from IBU."
+ {options/ibu identity})
+
+
+(defn convert
+ "Given a `bitterness` in `source-measurement`, convert it to the `target-measurement`.
+ Supported values for `source-measurement` and `target-measurement` are enumerated in [[bitterness-measurements]].
+ This function will throw an exception if unsupported measurement values are passed."
+ {:added "2.1"}
+ [bitterness source-measurement target-measurement]
+ (if (and (contains? measurements source-measurement)
+ (contains? measurements target-measurement)
+ (number? bitterness))
+ (if (= source-measurement target-measurement)
+ bitterness
+ (let [source->ibu-fn (measurement->ibu source-measurement)
+ ibu->target-fn (ibu->measurement target-measurement)]
+ (-> bitterness source->ibu-fn ibu->target-fn)))
+ (throw (ex-info "Unsupported bitterness conversion units"
+ {:source-measurement source-measurement
+ :target-measurement target-measurement
+ :allowed-values measurements
+ :bitterness bitterness}))))
+
+
+(defn display
+ "A function to render a human-readable `bitterness` in `source-units`.
+
+ For example,
+ ```clj
+ (display 10 options/ibu)
+ ;; => \"10 ibu\"
+ ```"
+ {:added "2.1"}
+ ([bitterness source-units]
+ (display bitterness source-units {}))
+ ([bitterness source-units {:keys [precision suffix]
+ :or {precision options/default-precision
+ suffix options/short}}]
+ (if (and (contains? measurements source-units)
+ (number? bitterness)
+ (integer? precision)
+ (contains? options/supported-suffixes suffix))
+ (let [display-name (get-in measurements->display-name [source-units suffix])]
+ (-> bitterness
+ (precision/->precision precision)
+ (str " " display-name)))
+ (throw (ex-info "Unsupported bitterness display units"
+ {:source-units source-units
+ :allowed-values measurements
+ :bitterness bitterness
+ :precision precision
+ :suffix suffix
+ :supported-suffixes options/supported-suffixes})))))
diff --git a/src/brewtility/units/carbonation.cljc b/src/brewtility/units/carbonation.cljc
new file mode 100644
index 0000000..9d50799
--- /dev/null
+++ b/src/brewtility/units/carbonation.cljc
@@ -0,0 +1,106 @@
+(ns brewtility.units.carbonation
+ "A namespace for converting between different units of carbonation.
+
+ In the BeerXML spec, carbonation is a measure of the amount of carbon dioxide dissolved in beer.
+ This namespace converts between that measure and other units.
+
+ Currently, brewtility supports the following types of carbonation:
+ - [volumes-of-co2](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages)
+ - [grams-per-liter](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages)"
+ {:added "2.1"}
+ (:require [brewtility.precision :as precision]
+ [brewtility.units.options :as options]))
+
+
+(def measurements
+ "The carbonation systems available across brewtility."
+ #{options/volumes-of-co2 options/grams-per-liter})
+
+
+(def measurements->display-name
+ "A map from carbonation system names to their full and short unit names."
+ {options/volumes-of-co2 {options/full "volumes of CO2"
+ options/short "vols"}
+ options/grams-per-liter {options/full "grams per liter"
+ options/short "g/L"}})
+
+
+(defn- volumes-of-co2->grams-per-liter
+ "An implementation function to convert `volumes-of-co2` to grams per liter"
+ {:no-doc true
+ :added "2.1"}
+ [volumes-of-co2]
+ (* 1.96 volumes-of-co2))
+
+
+(defn- grams-per-liter->volumes-of-co2
+ "An implementation function to convert `grams-per-liter` to volumes of CO2"
+ {:no-doc true
+ :added "2.1"}
+ [grams-per-liter]
+ (/ grams-per-liter 1.96))
+
+
+(def measurement->volumes-of-co2
+ "A map from carbonation system names to the conversion function to volumes of CO2."
+ {options/volumes-of-co2 identity
+ options/grams-per-liter volumes-of-co2->grams-per-liter})
+
+
+(def volumes-of-co2->measurement
+ "A map from carbonation system names to the conversion function from volumes of CO2."
+ {options/volumes-of-co2 identity
+ options/grams-per-liter grams-per-liter->volumes-of-co2})
+
+
+(defn convert
+ "Given a `carbonation` in `source-measurement`, convert it to the `target-measurement`.
+ Supported values for `source-measurement` and `target-measurement` are enumerated in [[carbonation-measurements]].
+ This function will throw an exception if unsupported measurement values are passed."
+ {:added "2.1"}
+ [carbonation source-measurement target-measurement]
+ (if (and (contains? measurements source-measurement)
+ (contains? measurements target-measurement)
+ (number? carbonation))
+ (if (= source-measurement target-measurement)
+ carbonation
+ (let [source->volumes-of-co2-fn (measurement->volumes-of-co2 source-measurement)
+ volumes-of-co2->target-fn (volumes-of-co2->measurement target-measurement)]
+ (-> carbonation source->volumes-of-co2-fn volumes-of-co2->target-fn)))
+ (throw (ex-info "Unsupported carbonation conversion units"
+ {:source-measurement source-measurement
+ :target-measurement target-measurement
+ :allowed-values measurements
+ :carbonation carbonation}))))
+
+
+(defn display
+ "A function to render a human-readable `carbonation` in `source-units`.
+
+ For example,
+ ```clj
+ (display 10 options/volumes-of-co2)
+ ;; => \"10 vols\"
+ ```"
+ {:added "2.1"}
+ ([carbonation source-units]
+ (display carbonation source-units {}))
+ ([carbonation source-units {:keys [precision suffix]
+ :or {precision options/default-precision
+ suffix options/short}}]
+ (if (and (contains? measurements source-units)
+ (number? carbonation)
+ (integer? precision)
+ (contains? options/supported-suffixes suffix))
+ (let [display-name (get-in measurements->display-name [source-units suffix])]
+ (-> carbonation
+ (convert source-units options/volumes-of-co2)
+ (precision/->precision precision)
+ (str " " display-name)))
+ (throw (ex-info "Unsupported carbonation display units"
+ {:source-units source-units
+ :allowed-values measurements
+ :carbonation carbonation
+ :precision precision
+ :suffix suffix
+ :supported-suffixes options/supported-suffixes})))))
diff --git a/src/brewtility/units/color.cljc b/src/brewtility/units/color.cljc
index 0c50262..0c4bd05 100644
--- a/src/brewtility/units/color.cljc
+++ b/src/brewtility/units/color.cljc
@@ -1,9 +1,9 @@
(ns brewtility.units.color
"A namespace for converting between different units of color.
-
+
In the BeerXML spec, color is measured in different units in different contexts.
This namespace provides a way to convert between SRM and other units of color.
-
+
Currently, brewtility supports the following types of color:
- [SRM](https://en.wikipedia.org/wiki/Standard_Reference_Method)
- [EBC](https://en.wikipedia.org/wiki/European_Brewery_Convention)
@@ -11,10 +11,11 @@
- [RGBa](https://en.wikipedia.org/wiki/RGBA_color_model)"
{:added "2.0"}
(:require [brewtility.precision :as precision]
- [brewtility.units.options :as options]))
+ [brewtility.units.options :as options]
+ [clojure.set :as set]))
-(def ^:const measurements
+(def measurements
"The color systems available across brewtility."
#{options/srm
options/ebc
@@ -22,7 +23,7 @@
options/rgba})
-(def ^:const measurements->display-name
+(def measurements->display-name
"A map from color system names to their full and short unit names"
{options/srm {options/full "standard reference method"
options/short "srm"}
@@ -284,6 +285,11 @@
40 srm-40})
+(def rgba-lookup-map
+ "A map of known RGBa color codes to their closest SRM value."
+ (set/map-invert srm-color-map))
+
+
(defn- lovibond->srm
"Convert the color described in degrees `lovibond` to the equivalent SRM color."
{:added "2.0"}
@@ -322,13 +328,23 @@
(get srm-color-map srm-color)))
+(defn- rgba->srm
+ "Given one of the known `rgba-string` color codes, return the closest SRM value."
+ {:added "2.1"}
+ [rgba-string]
+ (if-let [srm-value (get rgba-lookup-map rgba-string)]
+ srm-value
+ (throw (ex-info "Unsupported RGBa color value"
+ {:allowed-values (-> rgba-lookup-map keys set)
+ :color rgba-string}))))
+
+
(def measurement->srm
- "A map from color systems to the implementation function that converts to SRM.
-
- Note: RGBa is not included because it is not a color system, but a color representation."
+ "A map from color systems to the implementation function that converts to SRM."
{options/ebc ebc->srm
options/lovibond lovibond->srm
- options/srm identity})
+ options/srm identity
+ options/rgba rgba->srm})
(def srm->measurement
@@ -348,7 +364,9 @@
[color-val source-system target-system]
(if (and (contains? measurement->srm source-system)
(contains? measurements target-system)
- (number? color-val))
+ (if (= source-system options/rgba)
+ (string? color-val)
+ (number? color-val)))
(if (= source-system target-system)
color-val
(let [source->srm-fn (measurement->srm source-system)
diff --git a/src/brewtility/units/options.cljc b/src/brewtility/units/options.cljc
index b1f2676..41d480d 100644
--- a/src/brewtility/units/options.cljc
+++ b/src/brewtility/units/options.cljc
@@ -1,6 +1,6 @@
(ns brewtility.units.options
"A namespace of static symbolic keywords and values used in the option maps throughout brewtility.
-
+
Implemented as part of the Symbolic Keyword pattern."
{:added "2.0"}
(:refer-clojure :exclude [second short time]))
@@ -20,7 +20,7 @@
(def system-of-measure
"The system of measure used in the recipe or for a given unit.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Brewility supports the following systems of measure:
- [British imperial](https://en.wikipedia.org/wiki/Imperial_units)
@@ -35,7 +35,7 @@
(def imperial
"The [British imperial](https://en.wikipedia.org/wiki/Imperial_units) system of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:imperial)
@@ -45,7 +45,7 @@
(def metric
"The [metric system](https://en.wikipedia.org/wiki/Metric_system) of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:metric)
@@ -55,7 +55,7 @@
(def us-customary
"The [United States Customary Units](https://en.wikipedia.org/wiki/United_States_customary_units) system of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.."
:us)
@@ -65,24 +65,29 @@
(def international-system
"The [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units) system of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:si)
+(def systems-of-measure
+ "The set of supported measurement systems"
+ #{imperial international-system metric us-customary})
+
+
;; Enricher Setting Keys
(def precision
"The number of decimal places to which a value is rounded.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:precision)
(def suffix
"The type of suffix to add on to displayed units of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Brewility supports the following suffix types:
- `:short` - A short suffix. (e.g. \"tsp\" instead of \"teaspoon\")
@@ -91,9 +96,9 @@
(def short
- "A short suffix.
+ "A short suffix.
(e.g. \"tsp\" instead of \"teaspoon\")
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:short)
@@ -101,7 +106,7 @@
(def full
"The full name as a suffix.
(e.g. \"teaspoon\")
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:full)
@@ -111,9 +116,37 @@
#{short full})
+(def alcohol-content
+ "The alcohol content systems used in the recipe.
+
+ Commonly used with `brewtility.units.alcohol-content` and in argument/option maps.
+ Currently, brewtility supports the following types of alcohol content measurements:
+ - [abv](https://en.wikipedia.org/wiki/Alcohol_by_volume)"
+ :alcohol-content)
+
+
+(def bitterness
+ "The bitterness systems used in the recipe.
+
+ Commonly used with `brewtility.units.bitterness` and in argument/option maps.
+ Currently, brewtility supports the following types of bitterness measurements:
+ - [international-bitterness-units](https://en.wikipedia.org/wiki/International_bitterness_units)"
+ :bitterness)
+
+
+(def carbonation
+ "The carbonation systems used in the recipe.
+
+ Commonly used with `brewtility.units.carbonation` and in argument/option maps.
+ Currently, brewtility supports the following types of carbonation measurements:
+ - [volumes-of-co2](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages)
+ - [grams-per-liter](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages)"
+ :carbonation)
+
+
(def color
- "The color systems used in the recipe or for a given unit.
-
+ "The color systems used in the recipe.
+
Commonly used with `brewtility.units.color` and in argument/option maps.
Brewility supports the following color systems:
- [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method)
@@ -124,8 +157,8 @@
(def pressure
- "The pressure systems used in the recipe or for a given unit.
-
+ "The pressure systems used in the recipe.
+
Commonly used with `brewtility.units.pressure` and in argument/option maps.
Currently, brewtility supports the following types of pressure:
- [pascal](https://en.wikipedia.org/wiki/Pascal_(unit)#Multiples_and_submultiples)
@@ -138,8 +171,8 @@
(def specific-gravity
- "The specific gravity systems used in the recipe or for a given unit.
-
+ "The specific gravity systems used in the recipe.
+
Commonly used with `brewtility.units.specific-gravity` and in argument/option maps.
Currently, brewtility supports the following types of specific gravity:
Currently, brewtility supports the following types of specific gravity:
@@ -148,8 +181,8 @@
(def temperature
- "The temperature systems used in the recipe or for a given unit.
-
+ "The temperature systems used in the recipe.
+
Commonly used with `brewtility.units.temperature` and in argument/option maps.
Currently, brewtility supports the following types of temperature:
- [celsius](https://en.wikipedia.org/wiki/Celsius)
@@ -159,8 +192,8 @@
(def time
- "The time systems used in the recipe or for a given unit.
-
+ "The time systems used in the recipe.
+
Commonly used with `brewtility.units.time` and in argument/option maps.
Currently, brewtility supports the following types of time measurements:
- [microsecond](https://en.wikipedia.org/wiki/Microsecond)
@@ -175,8 +208,8 @@
(def volume
- "The volume systems used in the recipe or for a given unit.
-
+ "The volume systems used in the recipe.
+
Commonly used with `brewtility.units.volume` and in argument/option maps.
Currently, brewtility supports the following types of volume:
- [american-fluid-ounce](https://en.wikipedia.org/wiki/Fluid_ounce)
@@ -198,8 +231,8 @@
(def weight
- "The weight systems used in the recipe or for a given unit.
-
+ "The weight systems used in the recipe.
+
Commonly used with `brewtility.units.weight` and in argument/option maps.
Currently, brewtility supports the following types of weight:
- [gram](https://en.wikipedia.org/wiki/Gram)
@@ -212,7 +245,10 @@
(def measurement-types
"The measurement types available across brewtility."
- #{color
+ #{alcohol-content
+ bitterness
+ carbonation
+ color
pressure
specific-gravity
temperature
@@ -221,104 +257,144 @@
weight})
+;; Alcohol Content Systems
+(def abv
+ "The [Alcohol by Volume](https://en.wikipedia.org/wiki/Alcohol_by_volume) system of measure.
+
+ Commonly used with `brewtility.units.alcohol-content` and in argument/option maps."
+ :abv)
+
+
+;; Bitterness Systems
+(def ibu
+ "The [International Bitterness Units](https://en.wikipedia.org/wiki/International_bitterness_units) system of measure.
+
+ Commonly used with `brewtility.units.bitterness` and in argument/option maps."
+ :ibu)
+
+
+;; Carbonation Systems
+(def volumes-of-co2
+ "The [volumes of CO2](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages) system of measure.
+
+ Commonly used with `brewtility.units.carbonation` and in argument/option maps."
+ :volumes-of-co2)
+
+
+(def grams-per-liter
+ "The [grams per liter](https://en.wikipedia.org/wiki/Carbon_dioxide#Beverages) system of measure.
+
+ Commonly used with `brewtility.units.carbonation` and in argument/option maps."
+ :grams-per-liter)
+
+
;; Color Systems
(def srm
"The [Standard Reference Method](https://en.wikipedia.org/wiki/Standard_Reference_Method) color system.
-
+
Commonly used with `brewtility.units.color` and in argument/option maps."
:srm)
(def ebc
"The [European Brewery Convention](https://en.wikipedia.org/wiki/European_Brewery_Convention) color system.
-
+
Commonly used with `brewtility.units.color` and in argument/option maps."
:ebc)
(def lovibond
"The [Lovibond](https://en.wikipedia.org/wiki/Beer_measurement#Colour) color system.
-
+
Commonly used with `brewtility.units.color` and in argument/option maps."
:lovibond)
(def rgba
"The [RGBA](https://en.wikipedia.org/wiki/RGBA_color_space) color system.
-
+
Commonly used with `brewtility.units.color` and in argument/option maps."
:rgba)
+;; Specific Gravity Units
+
+(def plato
+ "The [Degrees Plato](https://en.wikipedia.org/wiki/Plato_scale#Extract) system of measure.
+
+ Commonly used with `brewtility.units.specific-gravity` and in argument/option maps."
+ :plato)
+
+
;; Volume Units
(def american-fluid-ounce
"The [American fluid ounce](https://en.wikipedia.org/wiki/Fluid_ounce#American_fluid_ounce) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:american-fluid-ounce)
(def american-gallon
"The [American gallon](https://en.wikipedia.org/wiki/Gallon#Us_liquid_gallon) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:american-gallon)
(def american-pint
"The [American pint](https://en.wikipedia.org/wiki/Pint#US_liquid_pint) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:american-pint)
(def american-quart
"The [American quart](https://en.wikipedia.org/wiki/Quart#US_liquid_quart) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:american-quart)
(def cup
"The [cup](https://en.wikipedia.org/wiki/Cup_(unit)) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:cup)
(def imperial-fluid-ounce
"The [Imperial fluid ounce](https://en.wikipedia.org/wiki/Fluid_ounce#Imperial_fluid_ounce) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:imperial-fluid-ounce)
(def imperial-gallon
"The [Imperial gallon](https://en.wikipedia.org/wiki/Gallon#Imperial_gallon) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:imperial-gallon)
(def imperial-pint
"The [Imperial pint](https://en.wikipedia.org/wiki/Pint#Imperial_pint) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:imperial-pint)
(def imperial-quart
"The [Imperial quart](https://en.wikipedia.org/wiki/Quart#Imperial_quart) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:imperial-quart)
(def liter
"The [liter](https://en.wikipedia.org/wiki/Liter) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: Both `litre` and `liter` are valid keys throughout brewtility to support regional spelling."
:liter)
@@ -326,7 +402,7 @@
(def litre
"The [liter](https://en.wikipedia.org/wiki/Litre) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: Both `litre` and `liter` are valid keys throughout brewtility to support regional spelling."
:litre)
@@ -334,7 +410,7 @@
(def milliliter
"The [milliliter](https://en.wikipedia.org/wiki/Milliliter) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: Both `millilitre` and `milliliter` are valid keys throughout brewtility to support regional spelling."
:milliliter)
@@ -342,7 +418,7 @@
(def millilitre
"The [milliliter](https://en.wikipedia.org/wiki/Millilitre) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: Both `millilitre` and `milliliter` are valid keys throughout brewtility to support regional spelling."
:millilitre)
@@ -350,14 +426,14 @@
(def teaspoon
"The [teaspoon](https://en.wikipedia.org/wiki/Teaspoon) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:teaspoon)
(def tablespoon
"The [tablespoon](https://en.wikipedia.org/wiki/Tablespoon) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:tablespoon)
@@ -366,35 +442,35 @@
(def gram
"The [gram](https://en.wikipedia.org/wiki/Gram) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:gram)
(def kilogram
"The [kilogram](https://en.wikipedia.org/wiki/Kilogram) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:kilogram)
(def milligram
"The [milligram](https://en.wikipedia.org/wiki/Milligram) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:milligram)
(def ounce
"The [ounce](https://en.wikipedia.org/wiki/Ounce#International_avoirdupois_ounce) unit of measure; specifically, the International avoirdupois ounce.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:ounce)
(def pound
"The [pound](https://en.wikipedia.org/wiki/Pound_(mass)) unit of measure
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:pound)
@@ -403,7 +479,7 @@
(def celsius
"The [Celsius](https://en.wikipedia.org/wiki/Celsius) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: `celsius`, `centigrade`, and `c` are all valid keys throughout brewtility to support multiple conventions."
:celsius)
@@ -411,7 +487,7 @@
(def c
"The [Celsius](https://en.wikipedia.org/wiki/Celsius) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: `celsius`, `centigrade`, and `c` are all valid keys throughout brewtility to support multiple conventions."
:c)
@@ -419,7 +495,7 @@
(def centigrade
"The [Celsius](https://en.wikipedia.org/wiki/Celsius) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: `celsius`, `centigrade`, and `c` are all valid keys throughout brewtility to support multiple conventions."
:centigrade)
@@ -427,7 +503,7 @@
(def fahrenheit
"The [Fahrenheit](https://en.wikipedia.org/wiki/Fahrenheit) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: `fahrenheit` and `f` are all valid keys throughout brewtility to support multiple conventions."
:fahrenheit)
@@ -435,7 +511,7 @@
(def f
"The [Fahrenheit](https://en.wikipedia.org/wiki/Fahrenheit) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: `fahrenheit` and `f` are all valid keys throughout brewtility to support multiple conventions."
:f)
@@ -443,7 +519,7 @@
(def kelvin
"The [Kelvin](https://en.wikipedia.org/wiki/Kelvin) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: `kelvin` and `k` are all valid keys throughout brewtility to support multiple conventions."
:kelvin)
@@ -451,7 +527,7 @@
(def k
"The [Kelvin](https://en.wikipedia.org/wiki/Kelvin) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps.
Note: `kelvin` and `k` are all valid keys throughout brewtility to support multiple conventions."
:k)
@@ -461,56 +537,56 @@
(def day
"The [day](https://en.wikipedia.org/wiki/Day) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:day)
(def hour
"The [hour](https://en.wikipedia.org/wiki/Hour) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:hour)
(def microsecond
"The [microsecond](https://en.wikipedia.org/wiki/Microsecond) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:microsecond)
(def millisecond
"The [millisecond](https://en.wikipedia.org/wiki/Millisecond) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:millisecond)
(def minute
"The [minute](https://en.wikipedia.org/wiki/Minute) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:minute)
(def nanosecond
"The [nanosecond](https://en.wikipedia.org/wiki/Nanosecond) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:nanosecond)
(def second
"The [second](https://en.wikipedia.org/wiki/Second) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:second)
(def week
"The [week](https://en.wikipedia.org/wiki/Week) unit of measure.
-
+
Commonly used with `brewtility.units` and in argument/option maps."
:week)
@@ -519,21 +595,21 @@
(def pascal
"The [Pascal](https://en.wikipedia.org/wiki/Pascal_(unit)) unit of measure.
-
+
Commonly used with `brewtility.units.pressure` and in argument maps."
:pascal)
(def kilopascal
"The [Kilopascal](https://en.wikipedia.org/wiki/Kilopascal) unit of measure.
-
+
Commonly used with `brewtility.units.pressure` and in argument maps."
:kilopascal)
(def bar
"The [Bar](https://en.wikipedia.org/wiki/Bar_(unit)) unit of measure.
-
+
Commonly used with `brewtility.units.pressure` and in argument maps."
:bar)
@@ -541,21 +617,21 @@
(def atmosphere
"The [Atmosphere](https://en.wikipedia.org/wiki/Atmosphere_(unit)) unit of measure.
Specifically, this is a [standard atmosphere](https://en.wikipedia.org/wiki/Standard_atmosphere).
-
+
Commonly used with `brewtility.units.pressure` and in argument maps."
:atmosphere)
(def torr
"The [Torr](https://en.wikipedia.org/wiki/Torr_(unit)) unit of measure.
-
+
Commonly used with `brewtility.units.pressure` and in argument maps."
:torr)
(def psi
"The [Pounds per square inch](https://en.wikipedia.org/wiki/Pound-force_per_square_inch) unit of measure.
-
+
Commonly used with `brewtility.units.pressure` and in argument maps."
:psi)
diff --git a/src/brewtility/units/pressure.cljc b/src/brewtility/units/pressure.cljc
index 26efaba..0967cc6 100644
--- a/src/brewtility/units/pressure.cljc
+++ b/src/brewtility/units/pressure.cljc
@@ -16,7 +16,7 @@
[brewtility.units.options :as options]))
-(def ^:const measurements
+(def measurements
"The pressure measurements supported by brewtility."
#{options/pascal
options/kilopascal
@@ -26,7 +26,7 @@
options/psi})
-(def ^:const measurements->display-name
+(def measurements->display-name
"A map of pressure measurements to their display names."
{options/pascal {options/full "pascal"
options/short "pa"}
@@ -122,7 +122,7 @@
(/ pressure 6.894757))
-(def ^:const measurement->kilopascal
+(def measurement->kilopascal
"A map of pressure measurements to functions that convert to kilopascals."
{options/pascal pascal->kilopascal
options/kilopascal identity
@@ -132,7 +132,7 @@
options/psi psi->kilopascal})
-(def ^:const kilopascal->measurement
+(def kilopascal->measurement
"A map of pressure measurements to functions that convert from kilopascals."
{options/pascal kilopascal->pascal
options/kilopascal identity
diff --git a/src/brewtility/units/specific_gravity.cljc b/src/brewtility/units/specific_gravity.cljc
index 808c4af..06a9c7d 100644
--- a/src/brewtility/units/specific_gravity.cljc
+++ b/src/brewtility/units/specific_gravity.cljc
@@ -1,9 +1,9 @@
(ns brewtility.units.specific-gravity
"A namespace for converting between different units of specific gravity.
-
+
In the BeerXML spec, specific gravity is measured in relative to the weight of the same size sample of water.
This namespace converts between that ratio and other units.
-
+
Currently, brewtility supports the following types of specific gravity:
- [specific-gravity](https://en.wikipedia.org/wiki/Specific_gravity)"
{:added "2.0"}
@@ -11,25 +11,49 @@
[brewtility.units.options :as options]))
-(def ^:const measurements
+(def measurements
"The specific gravity systems available across brewtility."
- #{options/specific-gravity})
+ #{options/specific-gravity options/plato})
-(def ^:const measurements->display-name
+(def measurements->display-name
"A map from specific gravity system names to their full and short unit names."
{options/specific-gravity {options/full "specific gravity"
- options/short "sg"}})
+ options/short "sg"}
+ options/plato {options/full "degrees plato"
+ options/short "°P"}})
+
+
+(defn- plato->specific-gravity
+ "Converts a `plato` value to a `specific-gravity` value."
+ {:added "2.1"
+ :no-doc true}
+ [plato]
+ (let [denom (- 258.6 (* (/ plato 258.2) 227.1))]
+ (+ 1 (/ plato denom))))
+
+
+(defn- specific-gravity->plato
+ "Converts a `specific-gravity` value to a `plato` value."
+ {:added "2.1"
+ :no-doc true}
+ [gravity]
+ (let [g1 (* 1111.14 gravity)
+ g2 (* 630.272 (Math/pow gravity 2))
+ g3 (* 135.997 (Math/pow gravity 3))]
+ (- (- (+ g1 g3) g2) 616.868)))
-(def ^:const measurement->specific-gravity
+(def measurement->specific-gravity
"A map from specific gravity system names to the conversion function to specific gravity."
- {options/specific-gravity identity})
+ {options/specific-gravity identity
+ options/plato plato->specific-gravity})
-(def ^:const specific-gravity->measurement
+(def specific-gravity->measurement
"A map from specific gravity system names to the conversion function from specific gravity."
- {options/specific-gravity identity})
+ {options/specific-gravity identity
+ options/plato specific-gravity->plato})
(defn convert
diff --git a/src/brewtility/units/temperature.cljc b/src/brewtility/units/temperature.cljc
index b7d3a9a..8d2b337 100644
--- a/src/brewtility/units/temperature.cljc
+++ b/src/brewtility/units/temperature.cljc
@@ -13,7 +13,7 @@
[brewtility.units.options :as options]))
-(def ^:const measurements
+(def measurements
"The temperature measurements supported by brewtility."
#{options/c
options/celsius
@@ -24,7 +24,7 @@
options/kelvin})
-(def ^:const measurements->display-name
+(def measurements->display-name
"The temperature measurements supported by brewtility."
{options/c {options/full "celsius"
options/short "c"}
@@ -74,7 +74,7 @@
(- temp 273.15))
-(def ^:const measurement->celsius
+(def measurement->celsius
"A map from measurement names to the implementation function which converts them to degrees celsius"
{options/c identity
options/celsius identity
@@ -85,7 +85,7 @@
options/kelvin kelvin->celsius})
-(def ^:const celsius->measurement
+(def celsius->measurement
"A map from measurement names to the implementation function which converts them from degrees celsius"
{options/celsius identity
options/c identity
diff --git a/src/brewtility/units/time.cljc b/src/brewtility/units/time.cljc
index 3b4bcee..df744ed 100644
--- a/src/brewtility/units/time.cljc
+++ b/src/brewtility/units/time.cljc
@@ -19,7 +19,7 @@
(:refer-clojure :exclude [time]))
-(def ^:const measurements
+(def measurements
"The time measurements available across brewtility"
#{options/day
options/hour
@@ -31,7 +31,7 @@
options/week})
-(def ^:const measurement->minute
+(def measurement->minute
"A map from measurement names to doubles representing their fractional value to one minute"
{options/day 1440.0
options/hour 60.0
@@ -43,7 +43,7 @@
options/week 10080.0})
-(def ^:const measurements->display-name
+(def measurements->display-name
"A map from measurement names to their full name and abbreviation"
{options/day {options/full "days"
options/short "d"}
diff --git a/src/brewtility/units/volume.cljc b/src/brewtility/units/volume.cljc
index 0c009a6..dd24f91 100644
--- a/src/brewtility/units/volume.cljc
+++ b/src/brewtility/units/volume.cljc
@@ -25,7 +25,7 @@
[brewtility.units.options :as options]))
-(def ^:const measurements
+(def measurements
"The volume measurements available across brewtility"
#{options/american-gallon
options/american-pint
@@ -44,7 +44,7 @@
options/imperial-fluid-ounce})
-(def ^:const measurement->litre
+(def measurement->litre
"A map from measurement names to doubles representing their fractional value to one liter"
{options/american-fluid-ounce 0.0295735
options/american-gallon 3.78541
@@ -63,7 +63,7 @@
options/teaspoon 0.00492892})
-(def ^:const measurements->display-name
+(def measurements->display-name
"A map from measurement names to their full name and abbreviation"
{options/american-fluid-ounce {options/full "fluid ounce"
options/short "fl oz"}
diff --git a/src/brewtility/units/weight.cljc b/src/brewtility/units/weight.cljc
index eb09fe8..e7a68d5 100644
--- a/src/brewtility/units/weight.cljc
+++ b/src/brewtility/units/weight.cljc
@@ -15,7 +15,7 @@
[brewtility.units.options :as options]))
-(def ^:const measurements
+(def measurements
"The weight measurements available across brewtility"
#{options/gram
options/kilogram
@@ -24,7 +24,7 @@
options/pound})
-(def ^:const measurement->kilogram
+(def measurement->kilogram
"A map from measurement names to doubles representing their fractional value to one kilogram"
{options/gram 0.001
options/kilogram 1.0
@@ -33,7 +33,7 @@
options/pound 0.45359237})
-(def ^:const measurements->display-name
+(def measurements->display-name
"A map from measurement names to their full name and abbreviation"
{options/gram {options/full "gram"
options/short "g"}
diff --git a/src/brewtility/wrapping.cljc b/src/brewtility/wrapping.cljc
index 6828586..53391ce 100644
--- a/src/brewtility/wrapping.cljc
+++ b/src/brewtility/wrapping.cljc
@@ -12,7 +12,9 @@
(defn wrap-equipment
"Wrap an `equipment` map into an `equipment-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-equipment"]}
+ :see-also ["unwrap-equipment"
+ "::common-beer-format.equipment/equipment"
+ "::common-beer-format.equipment/equipment-wrapper"]}
[equipment]
{:equipment equipment})
@@ -20,7 +22,9 @@
(defn unwrap-equipment
"Unwrap an `equipment-wrapper` map into an `equipment` map."
{:added "1.4"
- :see-also ["wrap-equipment"]}
+ :see-also ["wrap-equipment"
+ "::common-beer-format.equipment/equipment"
+ "::common-beer-format.equipment/equipment-wrapper"]}
[equipment-wrapper]
(:equipment equipment-wrapper))
@@ -30,7 +34,9 @@
(defn wrap-fermentables
"Wrap a `fermentables` collection into a `fermentables-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-fermentables"]}
+ :see-also ["unwrap-fermentables"
+ "::common-beer-format.fermentables/fermentables"
+ "::common-beer-format.fermentables/fermentables-wrapper"]}
[fermentables]
{:fermentables fermentables})
@@ -38,7 +44,9 @@
(defn unwrap-fermentables
"Unwrap a `fermentables-wrapper` map into a `fermentables` collection."
{:added "1.4"
- :see-also ["wrap-fermentables"]}
+ :see-also ["wrap-fermentables"
+ "::common-beer-format.fermentables/fermentables"
+ "::common-beer-format.fermentables/fermentables-wrapper"]}
[fermentables-wrapper]
(:fermentables fermentables-wrapper))
@@ -46,7 +54,9 @@
(defn wrap-fermentable
"Wrap a `fermentable` map into a `fermentable-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-fermentable"]}
+ :see-also ["unwrap-fermentable"
+ "::common-beer-format.fermentables/fermentable"
+ "::common-beer-format.fermentables/fermentable-wrapper"]}
[fermentable]
{:fermentable fermentable})
@@ -54,7 +64,9 @@
(defn unwrap-fermentable
"Unwrap a `fermentable-wrapper` map into a `fermentable` map."
{:added "1.4"
- :see-also ["wrap-fermentable"]}
+ :see-also ["wrap-fermentable"
+ "::common-beer-format.fermentables/fermentable"
+ "::common-beer-format.fermentables/fermentable-wrapper"]}
[fermentable-wrapper]
(:fermentable fermentable-wrapper))
@@ -64,7 +76,9 @@
(defn wrap-hops
"Wrap a `hops` collection into a `hops-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-hops"]}
+ :see-also ["unwrap-hops"
+ "::common-beer-format.hops/hops"
+ "::common-beer-format.hops/hops-wrapper"]}
[hops]
{:hops hops})
@@ -72,7 +86,9 @@
(defn unwrap-hops
"Unwrap a `hops-wrapper` map into a `hops` collection."
{:added "1.4"
- :see-also ["wrap-hops"]}
+ :see-also ["wrap-hops"
+ "::common-beer-format.hops/hops"
+ "::common-beer-format.hops/hops-wrapper"]}
[hops-wrapper]
(:hops hops-wrapper))
@@ -80,7 +96,9 @@
(defn wrap-hop
"Wrap a `hop` map into a `hop-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-hop"]}
+ :see-also ["unwrap-hop"
+ "::common-beer-format.hops/hop"
+ "::common-beer-format.hops/hop-wrapper"]}
[hop]
{:hop hop})
@@ -88,7 +106,9 @@
(defn unwrap-hop
"Unwrap a `hop-wrapper` map into a `hop` map."
{:added "1.4"
- :see-also ["wrap-hop"]}
+ :see-also ["wrap-hop"
+ "::common-beer-format.hops/hop"
+ "::common-beer-format.hops/hop-wrapper"]}
[hop-wrapper]
(:hop hop-wrapper))
@@ -98,7 +118,9 @@
(defn wrap-mash-step
"Wrap a `mash-step` map into a `mash-step-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-mash-step"]}
+ :see-also ["unwrap-mash-step"
+ "::common-beer-format.mash/mash-step"
+ "::common-beer-format.mash/mash-step-wrapper"]}
[mash-step]
{:mash-step mash-step})
@@ -106,7 +128,9 @@
(defn unwrap-mash-step
"Unwrap a `mash-step-wrapper` map into a `mash-step` map."
{:added "1.4"
- :see-also ["wrap-mash-step"]}
+ :see-also ["wrap-mash-step"
+ "::common-beer-format.mash/mash-step"
+ "::common-beer-format.mash/mash-step-wrapper"]}
[mash-step-wrapper]
(:mash-step mash-step-wrapper))
@@ -114,7 +138,9 @@
(defn wrap-mash
"Wrap a `mash` map into a `mash-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-mash"]}
+ :see-also ["unwrap-mash"
+ "::common-beer-format.mash/mash"
+ "::common-beer-format.mash/mash-wrapper"]}
[mash]
{:mash mash})
@@ -122,7 +148,9 @@
(defn unwrap-mash
"Unwrap a `mash-wrapper` map into a `mash` map."
{:added "1.4"
- :see-also ["wrap-mash"]}
+ :see-also ["wrap-mash"
+ "::common-beer-format.mash/mash"
+ "::common-beer-format.mash/mash-wrapper"]}
[mash-wrapper]
(:mash mash-wrapper))
@@ -132,7 +160,9 @@
(defn wrap-misc
"Wrap a `misc` map into a `misc-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-misc"]}
+ :see-also ["unwrap-misc"
+ "::common-beer-format.miscs/misc"
+ "::common-beer-format.miscs/misc-wrapper"]}
[misc]
{:misc misc})
@@ -140,7 +170,9 @@
(defn unwrap-misc
"Unwrap a `misc-wrapper` map into a `misc` map."
{:added "1.4"
- :see-also ["wrap-misc"]}
+ :see-also ["wrap-misc"
+ "::common-beer-format.miscs/misc"
+ "::common-beer-format.miscs/misc-wrapper"]}
[misc-wrapper]
(:misc misc-wrapper))
@@ -148,7 +180,9 @@
(defn wrap-miscs
"Wrap a `miscs` collection into a `miscs-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-miscs"]}
+ :see-also ["unwrap-miscs"
+ "::common-beer-format.miscs/miscs"
+ "::common-beer-format.miscs/miscs-wrapper"]}
[miscs]
{:miscs miscs})
@@ -156,7 +190,9 @@
(defn unwrap-miscs
"Unwrap a `miscs-wrapper` map into a `miscs` collection."
{:added "1.4"
- :see-also ["wrap-miscs"]}
+ :see-also ["wrap-miscs"
+ "::common-beer-format.miscs/miscs"
+ "::common-beer-format.miscs/miscs-wrapper"]}
[miscs-wrapper]
(:miscs miscs-wrapper))
@@ -166,7 +202,9 @@
(defn wrap-recipe
"Wrap a `recipe` map into a `recipe-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-recipe"]}
+ :see-also ["unwrap-recipe"
+ "::common-beer-format.recipes/recipe"
+ "::common-beer-format.recipes/recipe-wrapper"]}
[recipe]
{:recipe recipe})
@@ -174,7 +212,9 @@
(defn unwrap-recipe
"Unwrap a `recipe-wrapper` map into a `recipe` map."
{:added "1.4"
- :see-also ["wrap-recipe"]}
+ :see-also ["wrap-recipe"
+ "::common-beer-format.recipes/recipe"
+ "::common-beer-format.recipes/recipe-wrapper"]}
[recipe-wrapper]
(:recipe recipe-wrapper))
@@ -182,7 +222,9 @@
(defn wrap-recipes
"Wrap a `recipes` collection into a `recipes-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-recipes"]}
+ :see-also ["unwrap-recipes"
+ "::common-beer-format.recipes/recipes"
+ "::common-beer-format.recipes/recipes-wrapper"]}
[recipes]
{:recipes recipes})
@@ -190,7 +232,9 @@
(defn unwrap-recipes
"Unwrap a `recipes-wrapper` map into a `recipes` collection."
{:added "1.4"
- :see-also ["wrap-recipes"]}
+ :see-also ["wrap-recipes"
+ "::common-beer-format.recipes/recipes"
+ "::common-beer-format.recipes/recipes-wrapper"]}
[recipes-wrapper]
(:recipes recipes-wrapper))
@@ -200,7 +244,9 @@
(defn wrap-style
"Wrap a `style` map into a `style-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-style"]}
+ :see-also ["unwrap-style"
+ "::common-beer-format.styles/style"
+ "::common-beer-format.styles/style-wrapper"]}
[style]
{:style style})
@@ -208,7 +254,9 @@
(defn unwrap-style
"Unwrap a `style-wrapper` map into a `style` map."
{:added "1.4"
- :see-also ["wrap-style"]}
+ :see-also ["wrap-style"
+ "::common-beer-format.styles/style"
+ "::common-beer-format.styles/style-wrapper"]}
[style-wrapper]
(:style style-wrapper))
@@ -216,7 +264,9 @@
(defn wrap-styles
"Wrap a `styles` collection into a `styles-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-styles"]}
+ :see-also ["unwrap-styles"
+ "::common-beer-format.styles/styles"
+ "::common-beer-format.styles/styles-wrapper"]}
[styles]
{:styles styles})
@@ -224,7 +274,9 @@
(defn unwrap-styles
"Unwrap a `styles-wrapper` map into a `styles` collection."
{:added "1.4"
- :see-also ["wrap-styles"]}
+ :see-also ["wrap-styles"
+ "::common-beer-format.styles/styles"
+ "::common-beer-format.styles/styles-wrapper"]}
[styles-wrapper]
(:styles styles-wrapper))
@@ -234,7 +286,9 @@
(defn wrap-water
"Wrap a `water` map into a `water-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-water"]}
+ :see-also ["unwrap-water"
+ "::common-beer-format.waters/water"
+ "::common-beer-format.waters/water-wrapper"]}
[water]
{:water water})
@@ -242,7 +296,9 @@
(defn unwrap-water
"Unwrap a `water-wrapper` map into a `water` map."
{:added "1.4"
- :see-also ["wrap-water"]}
+ :see-also ["wrap-water"
+ "::common-beer-format.waters/water"
+ "::common-beer-format.waters/water-wrapper"]}
[water-wrapper]
(:water water-wrapper))
@@ -250,7 +306,9 @@
(defn wrap-waters
"Wrap a `waters` collection into a `waters-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-waters"]}
+ :see-also ["unwrap-waters"
+ "::common-beer-format.waters/waters"
+ "::common-beer-format.waters/waters-wrapper"]}
[waters]
{:waters waters})
@@ -258,7 +316,9 @@
(defn unwrap-waters
"Unwrap a `waters-wrapper` map into a `waters` collection."
{:added "1.4"
- :see-also ["wrap-waters"]}
+ :see-also ["wrap-waters"
+ "::common-beer-format.waters/waters"
+ "::common-beer-format.waters/waters-wrapper"]}
[waters-wrapper]
(:waters waters-wrapper))
@@ -268,7 +328,9 @@
(defn wrap-yeast
"Wrap a `yeast` map into a `yeast-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-yeast"]}
+ :see-also ["unwrap-yeast"
+ "::common-beer-format.yeasts/yeast"
+ "::common-beer-format.yeasts/yeast-wrapper"]}
[yeast]
{:yeast yeast})
@@ -276,7 +338,9 @@
(defn unwrap-yeast
"Unwrap a `yeast-wrapper` map into a `yeast` map."
{:added "1.4"
- :see-also ["wrap-yeast"]}
+ :see-also ["wrap-yeast"
+ "::common-beer-format.yeasts/yeast"
+ "::common-beer-format.yeasts/yeast-wrapper"]}
[yeast-wrapper]
(:yeast yeast-wrapper))
@@ -284,7 +348,9 @@
(defn wrap-yeasts
"Wrap a `yeasts` collection into a `yeasts-wrapper` map."
{:added "1.4"
- :see-also ["unwrap-yeasts"]}
+ :see-also ["unwrap-yeasts"
+ "::common-beer-format.yeasts/yeasts"
+ "::common-beer-format.yeasts/yeasts-wrapper"]}
[yeasts]
{:yeasts yeasts})
@@ -292,6 +358,8 @@
(defn unwrap-yeasts
"Unwrap a `yeasts-wrapper` map into a `yeasts` collection."
{:added "1.4"
- :see-also ["wrap-yeasts"]}
+ :see-also ["wrap-yeasts"
+ "::common-beer-format.yeasts/yeasts"
+ "::common-beer-format.yeasts/yeasts-wrapper"]}
[yeasts-wrapper]
(:yeasts yeasts-wrapper))
diff --git a/test/brewtility/calculations_test.cljc b/test/brewtility/calculations_test.cljc
index 7b3a7a6..afd5b4a 100644
--- a/test/brewtility/calculations_test.cljc
+++ b/test/brewtility/calculations_test.cljc
@@ -19,11 +19,15 @@
(is (= 22.046 (bp/->3dp (:amount normalized-grain))))
(is (= (dissoc normalized-adjunct :amount :color) (dissoc (:grits adjuncts/adjuncts) :amount :color)))
(is (= 11.023 (bp/->3dp (:amount normalized-adjunct))))
- (is (= 1.299 (bp/->3dp (:color normalized-adjunct)))))))
+ (is (= 1.299 (bp/->3dp (:color normalized-adjunct))))))
+ (testing "An exception is thrown when data is missing"
+ (let [grain (dissoc (:rye-malt grains/grains) :amount)]
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot calculate color with non-numeric values" (sut/normalize-fermentable grain))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot calculate color with non-numeric values" (sut/normalize-fermentable grain)))))))
(deftest calculate-malt-color-units-test
- (testing "Colors can be correctly computer for recipes"
+ (testing "Colors can be correctly calculated for recipes"
(let [grain-1 (assoc (:rye-malt grains/grains) :amount 7)
grain-2 (assoc (:pale-malt-2-row-us grains/grains) :amount 3)
adjunct-1 (assoc (:rice-hulls adjuncts/adjuncts) :amount 2)
@@ -38,15 +42,20 @@
(deftest gravity-conversion-test
- (testing "Potential gravity and gravity points can be computed correctly"
+ (testing "Potential gravity and gravity points can be calculated correctly"
(is (= 264.555 (bp/->3dp (sut/potential-gravity->gravity-points 1.04 3))))
(is (= 0.0 (bp/->3dp (sut/potential-gravity->gravity-points 1.0 5143))))
(is (= 1.043 (bp/->3dp (sut/gravity-points->potential-gravity 40 3.5))))
- (is (= 1.0 (bp/->3dp (sut/gravity-points->potential-gravity 0 3.5))))))
+ (is (= 1.0 (bp/->3dp (sut/gravity-points->potential-gravity 0 3.5)))))
+ (testing "An exception is thrown when data is missing"
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot calculate gravity points with non-numeric values" (sut/potential-gravity->gravity-points nil 3))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot calculate gravity points with non-numeric values" (sut/potential-gravity->gravity-points nil 3))))
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot calculate potential gravity with non-numeric values" (sut/gravity-points->potential-gravity 40 nil))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot calculate potential gravity with non-numeric values" (sut/gravity-points->potential-gravity 40 nil))))))
(deftest calculate-potential-gravity-test
- (testing "Gravity/ABV can be correctly computer for recipes"
+ (testing "Gravity/ABV can be correctly calculated for recipes"
(let [grain-1 (assoc (:rye-malt grains/grains) :amount 7)
grain-2 (assoc (:pale-malt-2-row-us grains/grains) :amount 3)
adjunct-1 (assoc (:rice-hulls adjuncts/adjuncts) :amount 2)
@@ -79,7 +88,7 @@
(deftest calculate-alpha-acid-units-test
- (testing "The amount of alpha acids release by a known quantity of hops can be computed"
+ (testing "The amount of alpha acids release by a known quantity of hops can be calculated"
(is (= 0.0 (bp/->3dp (sut/calculate-alpha-acid-units 0.0 0.5))))
(is (= 0.0 (bp/->3dp (sut/calculate-alpha-acid-units 0.05 0.0))))
(is (= 79.014 (bp/->3dp (sut/calculate-alpha-acid-units 0.14 (:alpha (:el-dorado hops/both))))))
@@ -94,7 +103,15 @@
(is (= 29.448 (bp/->3dp (sut/calculate-ibu-per-hop (assoc hop :amount 0.01 :time 60) 15 1.03))))
(is (= 32.12 (bp/->3dp (sut/calculate-ibu-per-hop (assoc hop :amount 0.01 :time 120) 15 1.03))))
(is (= 16.06 (bp/->3dp (sut/calculate-ibu-per-hop (assoc hop :amount 0.01 :time 120) 30 1.03))))
- (is (= 24.529 (bp/->3dp (sut/calculate-ibu-per-hop (assoc hop :amount 0.01 :time 120) 15 1.06)))))))
+ (is (= 24.529 (bp/->3dp (sut/calculate-ibu-per-hop (assoc hop :amount 0.01 :time 120) 15 1.06))))))
+ (testing "An exception is thrown when data required for the calculation is missing"
+ (let [hop (:el-dorado hops/both)]
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot calculate IBUs with non-numeric values" (sut/calculate-ibu-per-hop {} 15 1.03))))
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot calculate IBUs with non-numeric values" (sut/calculate-ibu-per-hop hop nil 1.03))))
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot calculate IBUs with non-numeric values" (sut/calculate-ibu-per-hop hop 15 nil))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot calculate IBUs with non-numeric values" (sut/calculate-ibu-per-hop {} 15 1.03))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot calculate IBUs with non-numeric values" (sut/calculate-ibu-per-hop hop nil 1.03))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot calculate IBUs with non-numeric values" (sut/calculate-ibu-per-hop hop 15 nil)))))))
(deftest calculate-recipe-ibus-test
diff --git a/test/brewtility/data/equipment.cljc b/test/brewtility/data/equipment.cljc
index 76b7864..ece2246 100644
--- a/test/brewtility/data/equipment.cljc
+++ b/test/brewtility/data/equipment.cljc
@@ -4,33 +4,33 @@
[clojure.spec.gen.alpha :as gen]
[com.wallbrew.spoon.spec :as spoon.spec]
[common-beer-format.equipment :as equipment.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(def sample-equipment
"A hard-coded sample equipment for static unit tests"
- {:batch-size 19.9
- :boil-size 26.2
- :boil-time 60.5
- :calc-boil-volume true
- :evap-rate 9.0
- :hop-utilization 100.5
- :lauter-deadspace 0.8
- :name "8 Gal pot with 5 gal Igloo Cooler"
- :notes "Popular all grain setup. 5 Gallon Gott or Igloo cooler as mash tun with false bottom, and 7-9 gallon brewpot capable of boiling at least 6 gallons of wort. Primarily used for single infusion mashes."
- :top-up-kettle 0.5
- :top-up-water 0.5
- :trub-chiller-loss 0.8
- :tun-specific-heat 0.3
- :tun-volume 19.9
- :tun-weight 2.5
- :version 1})
+ {equipment.format/batch-size 19.9
+ equipment.format/boil-size 26.2
+ equipment.format/boil-time 60.5
+ equipment.format/calc-boil-volume true
+ equipment.format/evap-rate 9.0
+ equipment.format/hop-utilization 100.5
+ equipment.format/lauter-deadspace 0.8
+ equipment.format/name "8 Gal pot with 5 gal Igloo Cooler"
+ equipment.format/notes "Popular all grain setup. 5 Gallon Gott or Igloo cooler as mash tun with false bottom, and 7-9 gallon brewpot capable of boiling at least 6 gallons of wort. Primarily used for single infusion mashes."
+ equipment.format/top-up-kettle 0.5
+ equipment.format/top-up-water 0.5
+ equipment.format/trub-chiller-loss 0.8
+ equipment.format/tun-specific-heat 0.3
+ equipment.format/tun-volume 19.9
+ equipment.format/tun-weight 2.5
+ equipment.format/version 1})
(def sample-equipment-wrapper
"A hard-coded sample equipment-wrapper for static unit tests"
- {:equipment sample-equipment})
+ {equipment.format/equipment sample-equipment})
(defn generate-equipment
diff --git a/test/brewtility/data/fermentables.cljc b/test/brewtility/data/fermentables.cljc
index 544030e..03fcc46 100644
--- a/test/brewtility/data/fermentables.cljc
+++ b/test/brewtility/data/fermentables.cljc
@@ -4,31 +4,31 @@
[clojure.spec.gen.alpha :as gen]
[com.wallbrew.spoon.spec :as spoon.spec]
[common-beer-format.fermentables :as fermentables.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(def sample-fermentable
"A hard-coded sample fermentable for static unit tests"
- {:amount 0.45
- :coarse-fine-diff 1.5
- :color 500.1
- :diastatic-power 0.0
- :max-in-batch 10.0
- :moisture 5.0
- :name "Black Barley"
- :notes "Unmalted roasted barley for stouts, porters"
- :origin "United States"
- :protein 13.2
- :supplier "Gnome Brew"
- :type "Grain"
- :version 1
- :yield 78.0})
+ {fermentables.format/amount 0.45
+ fermentables.format/coarse-fine-diff 1.5
+ fermentables.format/color 500.1
+ fermentables.format/diastatic-power 0.0
+ fermentables.format/max-in-batch 10.0
+ fermentables.format/moisture 5.0
+ fermentables.format/name "Black Barley"
+ fermentables.format/notes "Unmalted roasted barley for stouts, porters"
+ fermentables.format/origin "United States"
+ fermentables.format/protein 13.2
+ fermentables.format/supplier "Gnome Brew"
+ fermentables.format/type "Grain"
+ fermentables.format/version 1
+ fermentables.format/yield 78.0})
(def sample-fermentable-wrapper
"A hard-coded sample fermentable-wrapper for static unit tests"
- {:fermentable sample-fermentable})
+ {fermentables.format/fermentable sample-fermentable})
(def sample-fermentables
@@ -38,7 +38,7 @@
(def sample-fermentables-wrapper
"A hard-coded sample fermentables-wrapper for static unit tests"
- {:fermentables sample-fermentables})
+ {fermentables.format/fermentables sample-fermentables})
(defn generate-fermentable
diff --git a/test/brewtility/data/hops.cljc b/test/brewtility/data/hops.cljc
index 0ed0a19..7d59eae 100644
--- a/test/brewtility/data/hops.cljc
+++ b/test/brewtility/data/hops.cljc
@@ -5,8 +5,8 @@
[com.wallbrew.spoon.spec :as spoon.spec]
[com.wallbrew.spoon.string :as spoon.str]
[common-beer-format.hops :as hops.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(defn random-hop-type
@@ -43,18 +43,18 @@
(def sample-hop
"A hard-coded sample hop for static unit tests"
- {:alpha 5.0
- :amount 0.0638
- :name "Goldings, East Kent"
- :notes "Great all purpose UK hop for ales, stouts, porters"
- :time 60.1
- :use "Boil"
- :version 1})
+ {hops.format/alpha 5.0
+ hops.format/amount 0.0638
+ hops.format/name "Goldings, East Kent"
+ hops.format/notes "Great all purpose UK hop for ales, stouts, porters"
+ hops.format/time 60.1
+ hops.format/use "Boil"
+ hops.format/version 1})
(def sample-hop-wrapper
"A hard-coded sample hop-wrapper for static unit tests"
- {:hop sample-hop})
+ {hops.format/hop sample-hop})
(def sample-hops
@@ -64,7 +64,7 @@
(def sample-hops-wrapper
"A hard-coded sample hops-wrapper for static unit tests"
- {:hops sample-hops})
+ {hops.format/hops sample-hops})
(defn generate-hop
@@ -103,9 +103,9 @@
(testing "Since this library assumes common-beer-format data is utilized, make sure static test data conforms"
(is (spoon.spec/test-valid? ::hops.format/hop sample-hop)
"Static test data should conform to common-beer-format.hop/hop")
- (is (spoon.spec/test-valid? ::hops.format/hop (assoc sample-hop :type (random-hop-type)))
+ (is (spoon.spec/test-valid? ::hops.format/hop (assoc sample-hop hops.format/type (random-hop-type)))
"Static test data should conform to common-beer-format.hop/hop, even with an added optional type")
- (is (spoon.spec/test-valid? ::hops.format/hop (assoc sample-hop :form (random-hop-form)))
+ (is (spoon.spec/test-valid? ::hops.format/hop (assoc sample-hop hops.format/form (random-hop-form)))
"Static test data should conform to common-beer-format.hop/hop, even with an added optional form")
(is (spoon.spec/test-valid? ::hops.format/hop sample-hop)
"Static test data should conform to common-beer-format.hop/hop")
@@ -119,9 +119,9 @@
(deftest generative-test-data-check
(testing "Since this library assumes common-beer-format data is utilized, make sure generative test data conforms"
- (is (spoon.spec/test-valid? ::hops.format/hop (assoc (generate-hop) :type (random-hop-type)))
+ (is (spoon.spec/test-valid? ::hops.format/hop (assoc (generate-hop) hops.format/type (random-hop-type)))
"Generative test data should conform to common-beer-format.hop/hop, even with an added optional type")
- (is (spoon.spec/test-valid? ::hops.format/hop (assoc (generate-hop) :form (random-hop-form)))
+ (is (spoon.spec/test-valid? ::hops.format/hop (assoc (generate-hop) hops.format/form (random-hop-form)))
"Generative test data should conform to common-beer-format.hop/hop, even with an added optional form")
(is (spoon.spec/test-valid? ::hops.format/hop (generate-hop))
"Generative test data should conform to common-beer-format.hop/hop")
diff --git a/test/brewtility/data/mash.cljc b/test/brewtility/data/mash.cljc
index 99f3234..7789a25 100644
--- a/test/brewtility/data/mash.cljc
+++ b/test/brewtility/data/mash.cljc
@@ -4,23 +4,23 @@
[clojure.spec.gen.alpha :as gen]
[com.wallbrew.spoon.spec :as spoon.spec]
[common-beer-format.mash :as mash.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(def sample-mash-step
"A hard-coded sample mash step for static unit tests"
- {:infuse-amount 10.0
- :name "Conversion Step, 68C"
- :step-temp 68.0
- :step-time 60.0
- :type "Infusion"
- :version 1})
+ {mash.format/infuse-amount 10.0
+ mash.format/name "Conversion Step, 68C"
+ mash.format/step-temp 68.0
+ mash.format/step-time 60.0
+ mash.format/type "Infusion"
+ mash.format/version 1})
(def sample-mash-step-wrapper
"A hard-coded sample mash-step-wrapper for static unit tests"
- {:mash-step sample-mash-step})
+ {mash.format/mash-step sample-mash-step})
(def sample-mash-steps
@@ -28,12 +28,17 @@
[sample-mash-step-wrapper])
+(def sample-mash-steps-wrapper
+ "A hard-coded sample mash-steps-wrapper for static unit tests"
+ {mash.format/mash-steps sample-mash-steps})
+
+
(def sample-mash
"A hard-coded sample mash for static unit tests"
- {:name "Single Step Infusion, 68 C"
- :version 1
- :grain-temp 22.0
- :mash-steps sample-mash-steps})
+ {mash.format/name "Single Step Infusion, 68 C"
+ mash.format/version 1
+ mash.format/grain-temp 22.0
+ mash.format/mash-steps sample-mash-steps})
(def sample-mash-wrapper
@@ -65,6 +70,14 @@
(gen/generate (spec/gen ::mash.format/mash-steps)))
+(defn generate-mash-steps-wrapper
+ "Generate a random mash-steps object"
+ {:added "2.0"
+ :no-doc true}
+ []
+ {mash.format/mash-steps (gen/generate (spec/gen ::mash.format/mash-steps))})
+
+
(defn generate-mash
"Generate a random mash object"
{:added "1.4"
diff --git a/test/brewtility/data/miscs.cljc b/test/brewtility/data/miscs.cljc
index b40f46f..59ecf42 100644
--- a/test/brewtility/data/miscs.cljc
+++ b/test/brewtility/data/miscs.cljc
@@ -4,24 +4,24 @@
[clojure.spec.gen.alpha :as gen]
[com.wallbrew.spoon.spec :as spoon.spec]
[common-beer-format.miscs :as miscs.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(def sample-misc
"A hard-coded sample misc for static unit tests"
- {:amount 0.010
- :name "Irish Moss"
- :notes "Used as a clarifying agent during the last few minutes of the boil"
- :time 15.0
- :type "Fining"
- :use "Boil"
- :version 1})
+ {miscs.format/amount 0.010
+ miscs.format/name "Irish Moss"
+ miscs.format/notes "Used as a clarifying agent during the last few minutes of the boil"
+ miscs.format/time 15.1
+ miscs.format/type "Fining"
+ miscs.format/use "Boil"
+ miscs.format/version 1})
(def sample-misc-wrapper
"A hard-coded sample misc-wrapper for static unit tests"
- {:misc sample-misc})
+ {miscs.format/misc sample-misc})
(def sample-miscs
@@ -31,7 +31,7 @@
(def sample-miscs-wrapper
"A hard-coded sample miscs-wrapper for static unit tests"
- {:miscs sample-miscs})
+ {miscs.format/miscs sample-miscs})
(defn generate-misc
diff --git a/test/brewtility/data/recipes.cljc b/test/brewtility/data/recipes.cljc
index d7f6fe5..3abdb11 100644
--- a/test/brewtility/data/recipes.cljc
+++ b/test/brewtility/data/recipes.cljc
@@ -13,8 +13,8 @@
[com.wallbrew.spoon.spec :as spoon.spec]
[com.wallbrew.spoon.string :as spoon.str]
[common-beer-format.recipes :as recipes.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(defn random-ibu-method
@@ -35,24 +35,24 @@
(def sample-recipe
"A hard-coded sample recipe for static unit tests"
- (merge {:age 24.0
- :age-temp 17.0
- :batch-size 18.93
- :boil-size 20.82
- :boil-time 60.0
- :brewer "Brad Smith"
- :carbonation 2.1
- :carbonation-used "Kegged"
- :date "3 Jan 04"
- :efficiency 72.0
- :fermentation-stages 2
- :fg 1.012
- :name "Dry Stout"
- :og 1.036
- :rating "41"
- :taste-notes "Nice dry Irish stout with a warm body but low starting gravity much like the famous drafts."
- :type "All Grain"
- :version 1}
+ (merge {recipes.format/age 24.0
+ recipes.format/age-temp 17.0
+ recipes.format/batch-size 18.93
+ recipes.format/boil-size 20.82
+ recipes.format/boil-time 60.0
+ recipes.format/brewer "Brad Smith"
+ recipes.format/carbonation 2.1
+ recipes.format/carbonation-used "Kegged"
+ recipes.format/date "3 Jan 04"
+ recipes.format/efficiency 72.0
+ recipes.format/fermentation-stages 2
+ recipes.format/fg 1.012
+ recipes.format/name "Dry Stout"
+ recipes.format/og 1.036
+ recipes.format/taste-rating "41"
+ recipes.format/taste-notes "Nice dry Irish stout with a warm body but low starting gravity much like the famous drafts."
+ recipes.format/type "All Grain"
+ recipes.format/version 1}
equipment/sample-equipment-wrapper
fermentables/sample-fermentables-wrapper
hops/sample-hops-wrapper
@@ -65,7 +65,7 @@
(def sample-recipe-wrapper
"A hard-coded sample recipe-wrapper for static unit tests"
- {:recipe sample-recipe})
+ {recipes.format/recipe sample-recipe})
(def sample-recipes
@@ -75,7 +75,7 @@
(def sample-recipes-wrapper
"A hard-coded sample recipes-wrapper for static unit tests"
- {:recipes sample-recipes})
+ {recipes.format/recipes sample-recipes})
(defn generate-recipe
@@ -114,7 +114,7 @@
(testing "Since this library assumes common-beer-format data is utilized, make sure static test data conforms"
(is (spoon.spec/test-valid? ::recipes.format/recipe sample-recipe)
"Static test data should conform to common-beer-format.recipe/recipe")
- (is (spoon.spec/test-valid? ::recipes.format/recipe (assoc sample-recipe :ibu-method (random-ibu-method)))
+ (is (spoon.spec/test-valid? ::recipes.format/recipe (assoc sample-recipe recipes.format/ibu-method (random-ibu-method)))
"Static test data should conform to common-beer-format.recipe/recipe, even with a random IBU method")
(is (spoon.spec/test-valid? ::recipes.format/recipe-wrapper sample-recipe-wrapper)
"Static test data should conform to common-beer-format.recipe/recipe-wrapper")
@@ -128,7 +128,7 @@
(testing "Since this library assumes common-beer-format data is utilized, make sure generative test data conforms"
(is (spoon.spec/test-valid? ::recipes.format/recipe (generate-recipe))
"Generative test data should conform to common-beer-format.recipe/recipe")
- (is (spoon.spec/test-valid? ::recipes.format/recipe (assoc (generate-recipe) :ibu-method (random-ibu-method)))
+ (is (spoon.spec/test-valid? ::recipes.format/recipe (assoc (generate-recipe) recipes.format/ibu-method (random-ibu-method)))
"Generative test data should conform to common-beer-format.recipe/recipe, even with a random IBU method")
(is (spoon.spec/test-valid? ::recipes.format/recipe-wrapper (generate-recipe-wrapper))
"Generative test data should conform to common-beer-format.recipe/recipe-wrapper")
diff --git a/test/brewtility/data/styles.cljc b/test/brewtility/data/styles.cljc
index 41c744b..ed4bf68 100644
--- a/test/brewtility/data/styles.cljc
+++ b/test/brewtility/data/styles.cljc
@@ -1,40 +1,40 @@
(ns brewtility.data.styles
- "Namespace for static and generative test data for `common-beer-format.styles/*` specs."
+ "Namespace for static and generative test data for `common-beer-format.stylespec/*` specs."
(:require [clojure.spec.alpha :as spec]
[clojure.spec.gen.alpha :as gen]
[com.wallbrew.spoon.spec :as spoon.spec]
- [common-beer-format.styles :as style.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ [common-beer-format.styles :as styles.format]
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(def sample-style
"A hard-coded sample style for static unit tests"
- {:abv-max 5.5
- :abv-min 3.2
- :carb-max 2.1
- :carb-min 1.6
- :category "Stout"
- :category-number "16"
- :color-max 200.0
- :color-min 35.0
- :fg-max 1.011
- :fg-min 1.007
- :ibu-max 50.0
- :ibu-min 30.0
- :name "Dry Stout"
- :notes "Famous Irish Stout. Dry, roasted, almost coffee like flavor."
- :og-max 1.050
- :og-min 1.035
- :style-guide "BJCP"
- :style-letter "A"
- :type "Ale"
- :version 1})
+ {styles.format/abv-max 5.5
+ styles.format/abv-min 3.2
+ styles.format/carb-max 2.1
+ styles.format/carb-min 1.6
+ styles.format/category "Stout"
+ styles.format/category-number "16"
+ styles.format/color-max 200.0
+ styles.format/color-min 35.0
+ styles.format/fg-max 1.011
+ styles.format/fg-min 1.007
+ styles.format/ibu-max 50.0
+ styles.format/ibu-min 30.0
+ styles.format/name "Dry Stout"
+ styles.format/notes "Famous Irish Stout. Dry, roasted, almost coffee like flavor."
+ styles.format/og-max 1.050
+ styles.format/og-min 1.035
+ styles.format/style-guide "BJCP"
+ styles.format/style-letter "A"
+ styles.format/type "Ale"
+ styles.format/version 1})
(def sample-style-wrapper
"A hard-coded sample style-wrapper for static unit tests"
- {:style sample-style})
+ {styles.format/style sample-style})
(def sample-styles
@@ -44,7 +44,7 @@
(def sample-styles-wrapper
"A hard-coded sample styles-wrapper for static unit tests"
- {:styles sample-styles})
+ {styles.format/styles sample-styles})
(defn generate-style
@@ -52,7 +52,7 @@
{:added "1.4"
:no-doc true}
[]
- (gen/generate (spec/gen ::style.format/style)))
+ (gen/generate (spec/gen ::styles.format/style)))
(defn generate-style-wrapper
@@ -60,7 +60,7 @@
{:added "1.4"
:no-doc true}
[]
- (gen/generate (spec/gen ::style.format/style-wrapper)))
+ (gen/generate (spec/gen ::styles.format/style-wrapper)))
(defn generate-styles
@@ -68,7 +68,7 @@
{:added "1.4"
:no-doc true}
[]
- (gen/generate (spec/gen ::style.format/styles)))
+ (gen/generate (spec/gen ::styles.format/styles)))
(defn generate-styles-wrapper
@@ -76,28 +76,28 @@
{:added "1.4"
:no-doc true}
[]
- (gen/generate (spec/gen ::style.format/styles-wrapper)))
+ (gen/generate (spec/gen ::styles.format/styles-wrapper)))
(deftest static-test-data-check
(testing "Since this library assumes common-beer-format data is utilized, make sure static test data conforms"
- (is (spoon.spec/test-valid? ::style.format/style sample-style)
+ (is (spoon.spec/test-valid? ::styles.format/style sample-style)
"Static test data should conform to common-beer-format.style/style")
- (is (spoon.spec/test-valid? ::style.format/style-wrapper sample-style-wrapper)
+ (is (spoon.spec/test-valid? ::styles.format/style-wrapper sample-style-wrapper)
"Static test data should conform to common-beer-format.style/style-wrapper")
- (is (spoon.spec/test-valid? ::style.format/styles sample-styles)
+ (is (spoon.spec/test-valid? ::styles.format/styles sample-styles)
"Static test data should conform to common-beer-format.style/style")
- (is (spoon.spec/test-valid? ::style.format/styles-wrapper sample-styles-wrapper)
+ (is (spoon.spec/test-valid? ::styles.format/styles-wrapper sample-styles-wrapper)
"Static test data should conform to common-beer-format.style/style-wrapper")))
(deftest generative-test-data-check
(testing "Since this library assumes common-beer-format data is utilized, make sure generative test data conforms"
- (is (spoon.spec/test-valid? ::style.format/style (generate-style))
+ (is (spoon.spec/test-valid? ::styles.format/style (generate-style))
"Generative test data should conform to common-beer-format.style/style")
- (is (spoon.spec/test-valid? ::style.format/style-wrapper (generate-style-wrapper))
+ (is (spoon.spec/test-valid? ::styles.format/style-wrapper (generate-style-wrapper))
"Generative test data should conform to common-beer-format.style/style-wrapper")
- (is (spoon.spec/test-valid? ::style.format/styles (generate-styles))
+ (is (spoon.spec/test-valid? ::styles.format/styles (generate-styles))
"Generative test data should conform to common-beer-format.style/style")
- (is (spoon.spec/test-valid? ::style.format/styles-wrapper (generate-styles-wrapper))
+ (is (spoon.spec/test-valid? ::styles.format/styles-wrapper (generate-styles-wrapper))
"Generative test data should conform to common-beer-format.style/style-wrapper")))
diff --git a/test/brewtility/data/waters.cljc b/test/brewtility/data/waters.cljc
index 19b7144..1118935 100644
--- a/test/brewtility/data/waters.cljc
+++ b/test/brewtility/data/waters.cljc
@@ -4,13 +4,13 @@
[clojure.spec.gen.alpha :as gen]
[com.wallbrew.spoon.spec :as spoon.spec]
[common-beer-format.waters :as waters.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(defn random-ph
"Generate a random `:ph` value."
- {:added "1.4"
+ {:added "2.0"
:no-doc true}
[]
(rand 14))
@@ -23,22 +23,22 @@
(def sample-water
"A hard-coded sample water for static unit tests"
- {:amount 20.0
- :bicarbonate 300.0
- :calcium 295.0
- :chloride 25.0
- :magnesium 45.0
- :name "Chicago"
- :notes "The best there is"
- :ph 8.0
- :sodium 55.0
- :sulfate 725.0
- :version 1})
+ {waters.format/amount 20.0
+ waters.format/bicarbonate 300.0
+ waters.format/calcium 295.0
+ waters.format/chloride 25.0
+ waters.format/magnesium 45.0
+ waters.format/name "Chicago"
+ waters.format/notes "The best there is"
+ waters.format/ph 8.0
+ waters.format/sodium 55.0
+ waters.format/sulfate 725.0
+ waters.format/version 1})
(def sample-water-wrapper
"A hard-coded sample water-wrapper for static unit tests"
- {:water sample-water})
+ {waters.format/water sample-water})
(def sample-waters
@@ -48,12 +48,12 @@
(def sample-waters-wrapper
"A hard-coded sample waters-wrapper for static unit tests"
- {:waters sample-waters})
+ {waters.format/waters sample-waters})
(defn generate-water
"Generate a random water object"
- {:added "1.4"
+ {:added "2.0"
:no-doc true}
[]
(gen/generate (spec/gen ::waters.format/water)))
@@ -87,6 +87,8 @@
(testing "Since this library assumes common-beer-format data is utilized, make sure static test data conforms"
(is (spoon.spec/test-valid? ::waters.format/water sample-water)
"Static test data should conform to common-beer-format.water/water")
+ (is (spoon.spec/test-valid? ::waters.format/water (assoc sample-water waters.format/ph (random-ph)))
+ "Static test data should conform to common-beer-format.water/water")
(is (spoon.spec/test-valid? ::waters.format/water-wrapper sample-water-wrapper)
"Static test data should conform to common-beer-format.water/water-wrapper")
(is (spoon.spec/test-valid? ::waters.format/waters sample-waters)
diff --git a/test/brewtility/data/yeasts.cljc b/test/brewtility/data/yeasts.cljc
index 1095176..ea85c90 100644
--- a/test/brewtility/data/yeasts.cljc
+++ b/test/brewtility/data/yeasts.cljc
@@ -5,8 +5,8 @@
[com.wallbrew.spoon.spec :as spoon.spec]
[com.wallbrew.spoon.string :as spoon.str]
[common-beer-format.yeasts :as yeasts.format]
- #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
(defn random-flocculation
@@ -27,24 +27,24 @@
(def sample-yeast
"A hard-coded sample yeast for static unit tests"
- {:amount 0.250
- :attenuation 73.0
- :best-for "Irish Dry Stouts"
- :flocculation "Medium"
- :form "Liquid"
- :laboratory "Wyeast Labs"
- :max-temperature 22.2
- :min-temperature 16.7
- :name "Irish Ale"
- :notes "Dry, fruity flavor characteristic of stouts. Full bodied, dry, clean flavor."
- :product-id "1084"
- :type "Ale"
- :version 1})
+ {yeasts.format/amount 0.250
+ yeasts.format/attenuation 73.0
+ yeasts.format/best-for "Irish Dry Stouts"
+ yeasts.format/flocculation "Medium"
+ yeasts.format/form "Liquid"
+ yeasts.format/laboratory "Wyeast Labs"
+ yeasts.format/max-temperature 22.2
+ yeasts.format/min-temperature 16.7
+ yeasts.format/name "Irish Ale"
+ yeasts.format/notes "Dry, fruity flavor characteristic of stouts. Full bodied, dry, clean flavor."
+ yeasts.format/product-id "1084"
+ yeasts.format/type "Ale"
+ yeasts.format/version 1})
(def sample-yeast-wrapper
"A hard-coded sample yeast-wrapper for static unit tests"
- {:yeast sample-yeast})
+ {yeasts.format/yeast sample-yeast})
(def sample-yeasts
@@ -54,7 +54,7 @@
(def sample-yeasts-wrapper
"A hard-coded sample yeasts-wrapper for static unit tests"
- {:yeasts sample-yeasts})
+ {yeasts.format/yeasts sample-yeasts})
(defn generate-yeast
@@ -93,7 +93,7 @@
(testing "Since this library assumes common-beer-format data is utilized, make sure static test data conforms"
(is (spoon.spec/test-valid? ::yeasts.format/yeast sample-yeast)
"Static test data should conform to common-beer-format.yeast/yeast")
- (is (spoon.spec/test-valid? ::yeasts.format/yeast (assoc sample-yeast :flocculation (random-flocculation)))
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast (assoc sample-yeast yeasts.format/flocculation (random-flocculation)))
"Static test data should conform to common-beer-format.yeast/yeast, even with random flocculation")
(is (spoon.spec/test-valid? ::yeasts.format/yeast-wrapper sample-yeast-wrapper)
"Static test data should conform to common-beer-format.yeast/yeast-wrapper")
@@ -107,7 +107,7 @@
(testing "Since this library assumes common-beer-format data is utilized, make sure generative test data conforms"
(is (spoon.spec/test-valid? ::yeasts.format/yeast (generate-yeast))
"Generative test data should conform to common-beer-format.yeast/yeast")
- (is (spoon.spec/test-valid? ::yeasts.format/yeast (assoc (generate-yeast) :flocculation (random-flocculation)))
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast (assoc (generate-yeast) yeasts.format/flocculation (random-flocculation)))
"Generative test data should conform to common-beer-format.yeast/yeast, even with random flocculation")
(is (spoon.spec/test-valid? ::yeasts.format/yeast-wrapper (generate-yeast-wrapper))
"Generative test data should conform to common-beer-format.yeast/yeast-wrapper")
diff --git a/test/brewtility/enrich/equipment_test.cljc b/test/brewtility/enrich/equipment_test.cljc
new file mode 100644
index 0000000..2579f3f
--- /dev/null
+++ b/test/brewtility/enrich/equipment_test.cljc
@@ -0,0 +1,486 @@
+(ns brewtility.enrich.equipment-test
+ (:require [brewtility.data.equipment :as equipment.data]
+ [brewtility.enrich.equipment :as equipment.enrich]
+ [com.wallbrew.spoon.spec :as spoon.spec]
+ [common-beer-format.equipment :as equipment.format]
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+
+
+(deftest enrich-calculated-boil-size-tests
+ (testing "Ensure enrichment pattern works for calculating boil size"
+ (is (= 20.288
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-calculated-boil-size
+ :boil-size))
+ "Boil size can be derived in liters when sufficient data is present")
+ (is (= (:boil-size equipment.data/sample-equipment)
+ (-> equipment.data/sample-equipment
+ (dissoc :batch-size)
+ (equipment.enrich/enrich-calculated-boil-size {:safe-calculating-boil-size true})
+ :boil-size))
+ "Boil size will not be modified when required data for calculations are missing and `safe-calculating-boil-size` is true")
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot calculate boil volume with non-numeric values"
+ (-> equipment.data/sample-equipment
+ (dissoc :batch-size)
+ equipment.enrich/enrich-calculated-boil-size
+ :boil-size))
+ "Computation will throw an Exception when required data for calculations are missing and `safe-calculating-boil-size` is missing/false"))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot calculate boil volume with non-numeric values"
+ (-> equipment.data/sample-equipment
+ (dissoc :batch-size)
+ equipment.enrich/enrich-calculated-boil-size
+ :boil-size))
+ "Computation will throw an Exception when required data for calculations are missing and `safe-calculating-boil-size` is missing/false"))
+ (is (= "5.36 gal"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-calculated-boil-size
+ equipment.enrich/enrich-display-boil-size
+ :display-boil-size)))))
+
+
+(deftest enrich-display-boil-size-tests
+ (testing "Ensure enrichment pattern works for all displayable boil sizes"
+ (is (= "6.921 gal"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-display-boil-size
+ :display-boil-size))
+ "Boil size conversion defaults to US gallons and 3 significant figures of precision")
+ (is (= "6.92 gal"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-boil-size {:precision 2})
+ :display-boil-size))
+ "Boil size precision can be set to 2 significant figures")
+ (is (= "6.921 US gallon"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-boil-size {:suffix :full})
+ :display-boil-size))
+ "Boil size suffix can be set to full descriptive text")
+ (is (= "26.2 l"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-boil-size {:system-of-measure :metric})
+ :display-boil-size)))
+ (is (= "110.7 cup"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-boil-size {:boil-size-target-units :cup
+ :boil-size-precision 1
+ :boil-size-suffix :full})
+ :display-boil-size))
+ "Broad settings can be overridden with boil-size specific settings")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-boil-size equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")))
+
+
+(deftest enrich-display-batch-size-tests
+ (testing "Ensure enrichment pattern works for all displayable batch-sizes"
+ (is (= "5.257 gal"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-display-batch-size
+ :display-batch-size))
+ "batch-size conversion defaults to US gallons and 3 significant figures of precision")
+ (is (= "5.26 gal"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-batch-size {:precision 2})
+ :display-batch-size))
+ "batch-size precision can be set to 2 significant figures")
+ (is (= "5.257 US gallon"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-batch-size {:suffix :full})
+ :display-batch-size))
+ "batch-size suffix can be set to full descriptive text")
+ (is (= "19.9 l"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-batch-size {:system-of-measure :metric})
+ :display-batch-size)))
+ (is (= "84.1 cup"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-batch-size {:batch-size-target-units :cup
+ :batch-size-precision 1
+ :batch-size-suffix :full})
+ :display-batch-size))
+ "Broad settings can be overridden with batch-size specific settings")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-batch-size equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")))
+
+
+(deftest enrich-display-tun-volume-tests
+ (testing "Ensure enrichment pattern works for all displayable tun-volumes"
+ (is (= "5.257 gal"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-display-tun-volume
+ :display-tun-volume))
+ "tun-volume conversion defaults to US gallons and 3 significant figures of precision")
+ (is (= "5.26 gal"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-tun-volume {:precision 2})
+ :display-tun-volume))
+ "tun-volume precision can be set to 2 significant figures")
+ (is (= "5.257 US gallon"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-tun-volume {:suffix :full})
+ :display-tun-volume))
+ "tun-volume suffix can be set to full descriptive text")
+ (is (= "19.9 l"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-tun-volume {:system-of-measure :metric})
+ :display-tun-volume)))
+ (is (= "84.1 cup"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-tun-volume {:tun-volume-target-units :cup
+ :tun-volume-precision 1
+ :tun-volume-suffix :full})
+ :display-tun-volume))
+ "Broad settings can be overridden with tun-volume specific settings")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-tun-volume equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")))
+
+
+(deftest enrich-display-tun-weight-tests
+ (testing "Ensure enrichment pattern works for all displayable tun-weights"
+ (is (= "5.512 lb"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-display-tun-weight
+ :display-tun-weight))
+ "tun-weight conversion defaults to US gallons and 3 significant figures of precision")
+ (is (= "5.51 lb"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-tun-weight {:precision 2})
+ :display-tun-weight))
+ "tun-weight precision can be set to 2 significant figures")
+ (is (= "5.512 pound"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-tun-weight {:suffix :full})
+ :display-tun-weight))
+ "tun-weight suffix can be set to full descriptive text")
+ (is (= "2.5 kg"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-tun-weight {:system-of-measure :metric})
+ :display-tun-weight)))
+ (is (= "88.2 ounce"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-tun-weight {:tun-weight-target-units :ounce
+ :tun-weight-precision 1
+ :tun-weight-suffix :full})
+ :display-tun-weight))
+ "Broad settings can be overridden with tun-weight specific settings")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-tun-weight equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")))
+
+
+(deftest enrich-display-top-up-water-tests
+ (testing "Ensure enrichment pattern works for all displayable top-up-waters"
+ (is (= "0.132 gal"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-display-top-up-water
+ :display-top-up-water))
+ "top-up-water conversion defaults to US gallons and 3 significant figures of precision")
+ (is (= "0.13 gal"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-top-up-water {:precision 2})
+ :display-top-up-water))
+ "top-up-water precision can be set to 2 significant figures")
+ (is (= "0.132 US gallon"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-top-up-water {:suffix :full})
+ :display-top-up-water))
+ "top-up-water suffix can be set to full descriptive text")
+ (is (= "0.5 l"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-top-up-water {:system-of-measure :metric})
+ :display-top-up-water)))
+ (is (= "2.1 cup"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-top-up-water {:top-up-water-target-units :cup
+ :top-up-water-precision 1
+ :top-up-water-suffix :full})
+ :display-top-up-water))
+ "Broad settings can be overridden with top-up-water specific settings")
+ (is (nil? (-> equipment.data/sample-equipment
+ (dissoc :top-up-water)
+ equipment.enrich/enrich-display-top-up-water
+ :display-top-up-water))
+ ":display-top-up-water is not added if trub-chiller-loss is not present")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-top-up-water equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")))
+
+
+(deftest enrich-display-trub-chiller-loss-tests
+ (testing "Ensure enrichment pattern works for all displayable trub-chiller-losss"
+ (is (= "0.211 gal"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-display-trub-chiller-loss
+ :display-trub-chiller-loss))
+ "trub-chiller-loss conversion defaults to US gallons and 3 significant figures of precision")
+ (is (= "0.21 gal"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-trub-chiller-loss {:precision 2})
+ :display-trub-chiller-loss))
+ "trub-chiller-loss precision can be set to 2 significant figures")
+ (is (= "0.211 US gallon"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-trub-chiller-loss {:suffix :full})
+ :display-trub-chiller-loss))
+ "trub-chiller-loss suffix can be set to full descriptive text")
+ (is (= "0.8 l"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-trub-chiller-loss {:system-of-measure :metric})
+ :display-trub-chiller-loss)))
+ (is (= "3.4 cup"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-trub-chiller-loss {:trub-chiller-loss-target-units :cup
+ :trub-chiller-loss-precision 1
+ :trub-chiller-loss-suffix :full})
+ :display-trub-chiller-loss))
+ "Broad settings can be overridden with trub-chiller-loss specific settings")
+ (is (nil? (-> equipment.data/sample-equipment
+ (dissoc :trub-chiller-loss)
+ equipment.enrich/enrich-display-lauter-deadspace
+ :display-trub-chiller-loss))
+ ":display-trub-chiller-loss is not added if trub-chiller-loss is not present")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-trub-chiller-loss equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")))
+
+
+(deftest enrich-display-lauter-deadspace-tests
+ (testing "Ensure enrichment pattern works for all displayable lauter-deadspaces"
+ (is (= "0.211 gal"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-display-lauter-deadspace
+ :display-lauter-deadspace))
+ "lauter-deadspace conversion defaults to US gallons and 3 significant figures of precision")
+ (is (= "0.21 gal"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-lauter-deadspace {:precision 2})
+ :display-lauter-deadspace))
+ "lauter-deadspace precision can be set to 2 significant figures")
+ (is (= "0.211 US gallon"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-lauter-deadspace {:suffix :full})
+ :display-lauter-deadspace))
+ "lauter-deadspace suffix can be set to full descriptive text")
+ (is (= "0.8 l"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-lauter-deadspace {:system-of-measure :metric})
+ :display-lauter-deadspace)))
+ (is (= "3.4 cup"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-lauter-deadspace {:lauter-deadspace-target-units :cup
+ :lauter-deadspace-precision 1
+ :lauter-deadspace-suffix :full})
+ :display-lauter-deadspace))
+ "Broad settings can be overridden with lauter-deadspace specific settings")
+ (is (nil? (-> equipment.data/sample-equipment
+ (dissoc :lauter-deadspace)
+ (equipment.enrich/enrich-display-lauter-deadspace {:lauter-deadspace-target-units :cup
+ :lauter-deadspace-precision 1
+ :lauter-deadspace-suffix :full})
+ :display-lauter-deadspace))
+ "Display value will not be set if lauter-deadspace is not present")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-lauter-deadspace equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")))
+
+
+(deftest enrich-display-top-up-kettle-tests
+ (testing "Ensure enrichment pattern works for all displayable top-up-kettles"
+ (is (= "0.132 gal"
+ (-> equipment.data/sample-equipment
+ equipment.enrich/enrich-display-top-up-kettle
+ :display-top-up-kettle))
+ "top-up-kettle conversion defaults to US gallons and 3 significant figures of precision")
+ (is (= "0.13 gal"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-top-up-kettle {:precision 2})
+ :display-top-up-kettle))
+ "top-up-kettle precision can be set to 2 significant figures")
+ (is (= "0.132 US gallon"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-top-up-kettle {:suffix :full})
+ :display-top-up-kettle))
+ "top-up-kettle suffix can be set to full descriptive text")
+ (is (= "0.5 l"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-top-up-kettle {:system-of-measure :metric})
+ :display-top-up-kettle)))
+ (is (= "2.1 cup"
+ (-> equipment.data/sample-equipment
+ (equipment.enrich/enrich-display-top-up-kettle {:top-up-kettle-target-units :cup
+ :top-up-kettle-precision 1
+ :top-up-kettle-suffix :full})
+ :display-top-up-kettle))
+ "Broad settings can be overridden with top-up-kettle specific settings")
+ (is (nil? (-> equipment.data/sample-equipment
+ (dissoc :top-up-kettle)
+ equipment.enrich/enrich-display-top-up-kettle
+ :display-top-up-kettle))
+ ":display-top-up-kettle is not added if top-up-kettle is not present")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-top-up-kettle equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")))
+
+
+(deftest enrich-equipment-tests
+ (testing "Ensure enrichment pattern works for all equipment"
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-equipment equipment.data/sample-equipment))
+ "Enrichment pattern should produce a valid equipment object")
+ (is (= {:display-top-up-kettle "0.132 gal"
+ :display-batch-size "5.257 gal"
+ :lauter-deadspace 0.8
+ :calc-boil-volume true
+ :top-up-water 0.5
+ :hop-utilization 100.5
+ :name "8 Gal pot with 5 gal Igloo Cooler"
+ :display-top-up-water "0.132 gal"
+ :boil-size 20.288
+ :display-trub-chiller-loss "0.211 gal"
+ :display-lauter-deadspace "0.211 gal"
+ :trub-chiller-loss 0.8
+ :boil-time 60.5
+ :display-tun-weight "5.512 lb"
+ :notes "Popular all grain setup. 5 Gallon Gott or Igloo cooler as mash tun with false bottom, and 7-9 gallon brewpot capable of boiling at least 6 gallons of wort. Primarily used for single infusion mashes."
+ :tun-volume 19.9
+ :top-up-kettle 0.5
+ :display-tun-volume "5.257 gal"
+ :display-boil-size "5.36 gal"
+ :tun-weight 2.5
+ :version 1
+ :tun-specific-heat 0.3
+ :batch-size 19.9
+ :evap-rate 9.0}
+ (equipment.enrich/enrich-equipment equipment.data/sample-equipment)))
+ (is (= {:display-top-up-kettle "0.5 litre"
+ :display-batch-size "19.9 litre"
+ :lauter-deadspace 0.8
+ :calc-boil-volume true
+ :top-up-water 0.5
+ :hop-utilization 100.5
+ :name "8 Gal pot with 5 gal Igloo Cooler"
+ :display-top-up-water "0.5 litre"
+ :boil-size 20.3
+ :display-trub-chiller-loss "0.8 litre"
+ :display-lauter-deadspace "0.8 litre"
+ :trub-chiller-loss 0.8
+ :boil-time 60.5
+ :display-tun-weight "2.5 kilogram"
+ :notes "Popular all grain setup. 5 Gallon Gott or Igloo cooler as mash tun with false bottom, and 7-9 gallon brewpot capable of boiling at least 6 gallons of wort. Primarily used for single infusion mashes."
+ :tun-volume 19.9
+ :top-up-kettle 0.5
+ :display-tun-volume "19.9 litre"
+ :display-boil-size "20.3 litre"
+ :tun-weight 2.5
+ :version 1
+ :tun-specific-heat 0.3
+ :batch-size 19.9
+ :evap-rate 9.0}
+ (equipment.enrich/enrich-equipment equipment.data/sample-equipment {:system-of-measure :si
+ :precision 1
+ :suffix :full}))
+ "Composed enrichment pattern global settings set default behavior for all enrichers")))
+
+
+(deftest enrich-equipment-wrapper-tests
+ (testing "Ensure enrichment pattern works for all equipment-wrapper"
+ (is (spoon.spec/test-valid? ::equipment.format/equipment-wrapper
+ (equipment.enrich/enrich-equipment-wrapper equipment.data/sample-equipment-wrapper))
+ "Enrichment pattern should produce a valid equipment-wrapper object")
+ (is (= {:equipment {:display-top-up-kettle "0.132 gal"
+ :display-batch-size "5.257 gal"
+ :lauter-deadspace 0.8
+ :calc-boil-volume true
+ :top-up-water 0.5
+ :hop-utilization 100.5
+ :name "8 Gal pot with 5 gal Igloo Cooler"
+ :display-top-up-water "0.132 gal"
+ :boil-size 20.288
+ :display-trub-chiller-loss "0.211 gal"
+ :display-lauter-deadspace "0.211 gal"
+ :trub-chiller-loss 0.8
+ :boil-time 60.5
+ :display-tun-weight "5.512 lb"
+ :notes "Popular all grain setup. 5 Gallon Gott or Igloo cooler as mash tun with false bottom, and 7-9 gallon brewpot capable of boiling at least 6 gallons of wort. Primarily used for single infusion mashes."
+ :tun-volume 19.9
+ :top-up-kettle 0.5
+ :display-tun-volume "5.257 gal"
+ :display-boil-size "5.36 gal"
+ :tun-weight 2.5
+ :version 1
+ :tun-specific-heat 0.3
+ :batch-size 19.9
+ :evap-rate 9.0}}
+ (equipment.enrich/enrich-equipment-wrapper equipment.data/sample-equipment-wrapper)))
+ (is (= {:equipment {:display-top-up-kettle "0.5 litre"
+ :display-batch-size "19.9 litre"
+ :lauter-deadspace 0.8
+ :calc-boil-volume true
+ :top-up-water 0.5
+ :hop-utilization 100.5
+ :name "8 Gal pot with 5 gal Igloo Cooler"
+ :display-top-up-water "0.5 litre"
+ :boil-size 20.3
+ :display-trub-chiller-loss "0.8 litre"
+ :display-lauter-deadspace "0.8 litre"
+ :trub-chiller-loss 0.8
+ :boil-time 60.5
+ :display-tun-weight "2.5 kilogram"
+ :notes "Popular all grain setup. 5 Gallon Gott or Igloo cooler as mash tun with false bottom, and 7-9 gallon brewpot capable of boiling at least 6 gallons of wort. Primarily used for single infusion mashes."
+ :tun-volume 19.9
+ :top-up-kettle 0.5
+ :display-tun-volume "19.9 litre"
+ :display-boil-size "20.3 litre"
+ :tun-weight 2.5
+ :version 1
+ :tun-specific-heat 0.3
+ :batch-size 19.9
+ :evap-rate 9.0}}
+ (equipment.enrich/enrich-equipment-wrapper equipment.data/sample-equipment-wrapper {:system-of-measure :si
+ :precision 1
+ :suffix :full}))
+ "Composed enrichment pattern global settings set default behavior for all enrichers")))
+
+
+(deftest generative-enrichment-tests
+ (testing "Ensure enrichment pattern works against arbitrary equipment"
+ ;; We disable boil voulme calculation in generative tests because :boil-size must be positive
+ ;; Which puts tight constraints on the test data, meaning actual generation of values would be
+ ;; extremely unlikely or require highly complex generators.
+ (letfn [(gen-equipment [] (assoc (equipment.data/generate-equipment) :calc-boil-volume false))]
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-boil-size (gen-equipment)))
+ "enrich-display-boil-size is a function to and from common-beer-format.equipment/equipment")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-batch-size (gen-equipment)))
+ "enrich-display-batch-size is a function to and from common-beer-format.equipment/equipment")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-tun-volume (gen-equipment)))
+ "enrich-display-tun-volume is a function to and from common-beer-format.equipment/equipment")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-tun-weight (gen-equipment)))
+ "enrich-display-tun-weight is a function to and from common-beer-format.equipment/equipment")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-top-up-water (gen-equipment)))
+ "enrich-display-top-up-water is a function to and from common-beer-format.equipment/equipment")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-trub-chiller-loss (gen-equipment)))
+ "enrich-display-trub-chiller-loss is a function to and from common-beer-format.equipment/equipment")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-lauter-deadspace (gen-equipment)))
+ "enrich-display-lauter-deadspace is a function to and from common-beer-format.equipment/equipment")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-display-top-up-kettle (gen-equipment)))
+ "enrich-display-top-up-kettle is a function to and from common-beer-format.equipment/equipment")
+ (is (spoon.spec/test-valid? ::equipment.format/equipment
+ (equipment.enrich/enrich-equipment (gen-equipment)))
+ "enrich-equipment is a function to and from common-beer-format.equipment/equipment")))
+ (testing "Ensure enrichment pattern works against arbitrary equipment wrappers"
+ (is (spoon.spec/test-valid? ::equipment.format/equipment-wrapper
+ (equipment.enrich/enrich-equipment-wrapper
+ (assoc-in (equipment.data/generate-equipment-wrapper) [:equipment :calc-boil-volume] false)))
+ "enrich-equipment-wrapper is a function to and from common-beer-format.equipment/equipment-wrapper")))
+
diff --git a/test/brewtility/enrich/fermentables_test.cljc b/test/brewtility/enrich/fermentables_test.cljc
new file mode 100644
index 0000000..a36bd7c
--- /dev/null
+++ b/test/brewtility/enrich/fermentables_test.cljc
@@ -0,0 +1,206 @@
+(ns brewtility.enrich.fermentables-test
+ (:require [brewtility.data.fermentables :as fermentable.data]
+ [brewtility.enrich.fermentables :as fermentable.enrich]
+ [com.wallbrew.spoon.spec :as spoon.spec]
+ [common-beer-format.fermentables :as fermentable.format]
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+
+
+(deftest enrich-add-after-boil-test
+ (testing "add-after-boil can be derived from a fermentable"
+ (is (boolean? (:add-after-boil (fermentable.enrich/enrich-add-after-boil (fermentable.data/generate-fermentable))))
+ "enrich-add-after-boil is a function from a fermentable to a map with a boolean add-after-boil key")
+ (is (boolean? (:add-after-boil (fermentable.enrich/enrich-add-after-boil fermentable.data/sample-fermentable)))
+ "enrich-add-after-boil is a function from a fermentable to a map with a boolean add-after-boil key")
+ (is (true? (-> fermentable.data/sample-fermentable
+ (assoc :add-after-boil true)
+ fermentable.enrich/enrich-add-after-boil
+ :add-after-boil))
+ "enrich-add-after-boil adds true when the add-after-boil key is truthy")
+ (is (false? (-> fermentable.data/sample-fermentable
+ (assoc :add-after-boil false)
+ fermentable.enrich/enrich-add-after-boil
+ :add-after-boil))
+ "enrich-add-after-boil adds false when the add-after-boil key is falsy")
+ (is (false? (-> fermentable.data/sample-fermentable
+ (dissoc :add-after-boil)
+ fermentable.enrich/enrich-add-after-boil
+ :add-after-boil))
+ "enrich-add-after-boil adds false when the add-after-boil key is nil")))
+
+
+(deftest enrich-coarse-fine-diff-test
+ (let [sample-grain (assoc fermentable.data/sample-fermentable :type "grain")
+ sample-adjunct (assoc fermentable.data/sample-fermentable :type "adjunct")
+ sample-extract (assoc fermentable.data/sample-fermentable :type "extract")
+ sample-dry-extract (assoc fermentable.data/sample-fermentable :type "dry extract")
+ sample-sugar (assoc fermentable.data/sample-fermentable :type "sugar")]
+ (testing "coarse-fine-diff is only applicable for grains and adjuncts"
+ (is (some? (:coarse-fine-diff (fermentable.enrich/enrich-coarse-fine-diff sample-grain))))
+ (is (some? (:coarse-fine-diff (fermentable.enrich/enrich-coarse-fine-diff sample-adjunct)))))
+ (testing "coarse-fine-diff is not applicable for any other types"
+ (is (nil? (:coarse-fine-diff (fermentable.enrich/enrich-coarse-fine-diff sample-extract))))
+ (is (nil? (:coarse-fine-diff (fermentable.enrich/enrich-coarse-fine-diff sample-dry-extract))))
+ (is (nil? (:coarse-fine-diff (fermentable.enrich/enrich-coarse-fine-diff sample-sugar)))))))
+
+
+(deftest enrich-moisture-test
+ (let [sample-grain (assoc fermentable.data/sample-fermentable :type "grain")
+ sample-adjunct (assoc fermentable.data/sample-fermentable :type "adjunct")
+ sample-extract (assoc fermentable.data/sample-fermentable :type "extract")
+ sample-dry-extract (assoc fermentable.data/sample-fermentable :type "dry extract")
+ sample-sugar (assoc fermentable.data/sample-fermentable :type "sugar")]
+ (testing "moisture is only applicable for grains and adjuncts"
+ (is (some? (:moisture (fermentable.enrich/enrich-moisture sample-grain))))
+ (is (some? (:moisture (fermentable.enrich/enrich-moisture sample-adjunct)))))
+ (testing "moisture is not applicable for any other types"
+ (is (nil? (:moisture (fermentable.enrich/enrich-moisture sample-extract))))
+ (is (nil? (:moisture (fermentable.enrich/enrich-moisture sample-dry-extract))))
+ (is (nil? (:moisture (fermentable.enrich/enrich-moisture sample-sugar)))))))
+
+
+(deftest enrich-diastatic-power-test
+ (let [sample-grain (assoc fermentable.data/sample-fermentable :type "grain")
+ sample-adjunct (assoc fermentable.data/sample-fermentable :type "adjunct")
+ sample-extract (assoc fermentable.data/sample-fermentable :type "extract")
+ sample-dry-extract (assoc fermentable.data/sample-fermentable :type "dry extract")
+ sample-sugar (assoc fermentable.data/sample-fermentable :type "sugar")]
+ (testing "diastatic-power is only applicable for grains and adjuncts"
+ (is (some? (:diastatic-power (fermentable.enrich/enrich-diastatic-power sample-grain))))
+ (is (some? (:diastatic-power (fermentable.enrich/enrich-diastatic-power sample-adjunct)))))
+ (testing "diastatic-power is not applicable for any other types"
+ (is (nil? (:diastatic-power (fermentable.enrich/enrich-diastatic-power sample-extract))))
+ (is (nil? (:diastatic-power (fermentable.enrich/enrich-diastatic-power sample-dry-extract))))
+ (is (nil? (:diastatic-power (fermentable.enrich/enrich-diastatic-power sample-sugar)))))))
+
+
+(deftest enrich-protein-test
+ (let [sample-grain (assoc fermentable.data/sample-fermentable :type "grain")
+ sample-adjunct (assoc fermentable.data/sample-fermentable :type "adjunct")
+ sample-extract (assoc fermentable.data/sample-fermentable :type "extract")
+ sample-dry-extract (assoc fermentable.data/sample-fermentable :type "dry extract")
+ sample-sugar (assoc fermentable.data/sample-fermentable :type "sugar")]
+ (testing "protein is only applicable for grains and adjuncts"
+ (is (some? (:protein (fermentable.enrich/enrich-protein sample-grain))))
+ (is (some? (:protein (fermentable.enrich/enrich-protein sample-adjunct)))))
+ (testing "protein is not applicable for any other types"
+ (is (nil? (:protein (fermentable.enrich/enrich-protein sample-extract))))
+ (is (nil? (:protein (fermentable.enrich/enrich-protein sample-dry-extract))))
+ (is (nil? (:protein (fermentable.enrich/enrich-protein sample-sugar)))))))
+
+
+(deftest enrich-recommend-mash-test
+ (let [sample-grain (assoc fermentable.data/sample-fermentable :type "grain")
+ sample-adjunct (assoc fermentable.data/sample-fermentable :type "adjunct")
+ sample-extract (assoc fermentable.data/sample-fermentable :type "extract")
+ sample-dry-extract (assoc fermentable.data/sample-fermentable :type "dry extract")
+ sample-sugar (assoc fermentable.data/sample-fermentable :type "sugar")]
+ (testing "recommend-mash is only applicable for grains and adjuncts"
+ (is (true? (:recommend-mash (fermentable.enrich/enrich-recommend-mash sample-grain))))
+ (is (true? (:recommend-mash (fermentable.enrich/enrich-recommend-mash sample-adjunct)))))
+ (testing "recommend-mash is not applicable for any other types"
+ (is (false? (:recommend-mash (fermentable.enrich/enrich-recommend-mash sample-extract))))
+ (is (false? (:recommend-mash (fermentable.enrich/enrich-recommend-mash sample-dry-extract))))
+ (is (false? (:recommend-mash (fermentable.enrich/enrich-recommend-mash sample-sugar)))))))
+
+
+(deftest enrich-ibu-gal-per-lb-test
+ (let [sample-grain (assoc fermentable.data/sample-fermentable :type "grain" :ibu-gal-per-lb 0.123)
+ sample-adjunct (assoc fermentable.data/sample-fermentable :type "adjunct" :ibu-gal-per-lb 0.123)
+ sample-extract (assoc fermentable.data/sample-fermentable :type "extract" :ibu-gal-per-lb 0.123)
+ sample-dry-extract (assoc fermentable.data/sample-fermentable :type "dry extract" :ibu-gal-per-lb 0.123)
+ sample-sugar (assoc fermentable.data/sample-fermentable :type "sugar" :ibu-gal-per-lb 0.123)]
+ (testing "ibu-gal-per-lb is only applicable for extracts"
+ (is (some? (:ibu-gal-per-lb (fermentable.enrich/enrich-ibu-gallons-per-pound sample-extract)))))
+ (testing "ibu-gal-per-lb is not applicable for any other types"
+ (is (nil? (:ibu-gal-per-lb (fermentable.enrich/enrich-ibu-gallons-per-pound sample-grain))))
+ (is (nil? (:ibu-gal-per-lb (fermentable.enrich/enrich-ibu-gallons-per-pound sample-adjunct))))
+ (is (nil? (:ibu-gal-per-lb (fermentable.enrich/enrich-ibu-gallons-per-pound sample-dry-extract))))
+ (is (nil? (:ibu-gal-per-lb (fermentable.enrich/enrich-ibu-gallons-per-pound sample-sugar)))))))
+
+
+;;
+;; Whole object enrichment tests
+;;
+
+(deftest enrich-fermentable-tests
+ (testing "Ensure enrichment pattern functions generate conforming data"
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-fermentable fermentable.data/sample-fermentable))
+ "Enrichment pattern should produce a valid fermentable object")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable-wrapper
+ (fermentable.enrich/enrich-fermentable-wrapper fermentable.data/sample-fermentable-wrapper))
+ "Enrichment pattern should produce a valid fermentable object")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentables
+ (fermentable.enrich/enrich-fermentables fermentable.data/sample-fermentables))
+ "Enrichment pattern should produce a valid fermentable object")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentables-wrapper
+ (fermentable.enrich/enrich-fermentables-wrapper fermentable.data/sample-fermentables-wrapper))
+ "Enrichment pattern should produce a valid fermentable object")
+ (testing "Static data comparison for enrichment pattern functions"
+ (is (= {:amount 0.45
+ :yield 78.0
+ :supplier "Gnome Brew"
+ :color 500.1
+ :display-color "500.1 °L"
+ :name "Black Barley"
+ :moisture 5.0
+ :type "Grain"
+ :add-after-boil false
+ :display-amount "0.992 lb"
+ :notes "Unmalted roasted barley for stouts, porters"
+ :protein 13.2
+ :origin "United States"
+ :coarse-fine-diff 1.5
+ :version 1
+ :max-in-batch 10.0
+ :recommend-mash true
+ :diastatic-power 0.0}
+ (fermentable.enrich/enrich-fermentable fermentable.data/sample-fermentable))))))
+
+
+(deftest generative-enrichment-tests
+ (testing "Ensure enrichment pattern works against arbitrary fermentable"
+ (letfn [(gen-fermentable [] (fermentable.data/generate-fermentable))]
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-add-after-boil (gen-fermentable)))
+ "enrich-add-after-boil is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-coarse-fine-diff (gen-fermentable)))
+ "enrich-coarse-fine-diff is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-moisture (gen-fermentable)))
+ "enrich-moisture is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-diastatic-power (gen-fermentable)))
+ "enrich-diastatic-power is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-protein (gen-fermentable)))
+ "enrich-protein is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-recommend-mash (gen-fermentable)))
+ "enrich-recommend-mash is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-ibu-gallons-per-pound (gen-fermentable)))
+ "enrich-ibu-gallons-per-pound is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-display-color (gen-fermentable)))
+ "enrich-display-color is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-display-amount (gen-fermentable)))
+ "enrich-display-amount is a function to and from common-beer-format.fermentable/fermentable")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable
+ (fermentable.enrich/enrich-fermentable (gen-fermentable)))
+ "enrich-fermentable is a function to and from common-beer-format.fermentable/fermentable")))
+ (testing "Ensure enrichment pattern works against arbitrary fermentable wrappers"
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentable-wrapper
+ (fermentable.enrich/enrich-fermentable-wrapper (fermentable.data/generate-fermentable-wrapper)))
+ "enrich-fermentable-wrapper is a function to and from common-beer-format.fermentable/fermentable-wrapper")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentables
+ (fermentable.enrich/enrich-fermentables (fermentable.data/generate-fermentables)))
+ "enrich-fermentables is a function to and from common-beer-format.fermentable/fermentables")
+ (is (spoon.spec/test-valid? ::fermentable.format/fermentables-wrapper
+ (fermentable.enrich/enrich-fermentables-wrapper (fermentable.data/generate-fermentables-wrapper)))
+ "enrich-fermentables-wrapper is a function to and from common-beer-format.fermentable/fermentables-wrapper")))
+
diff --git a/test/brewtility/enrich/hops_test.cljc b/test/brewtility/enrich/hops_test.cljc
new file mode 100644
index 0000000..ffaaa8d
--- /dev/null
+++ b/test/brewtility/enrich/hops_test.cljc
@@ -0,0 +1,60 @@
+(ns brewtility.enrich.hops-test
+ (:require [brewtility.data.hops :as hop.data]
+ [brewtility.enrich.hops :as hop.enrich]
+ [com.wallbrew.spoon.spec :as spoon.spec]
+ [common-beer-format.hops :as hop.format]
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+
+
+;;
+;; Whole object enrichment tests
+;;
+
+(deftest enrich-hop-tests
+ (testing "Ensure enrichment pattern functions generate conforming data"
+ (is (spoon.spec/test-valid? ::hop.format/hop
+ (hop.enrich/enrich-hop hop.data/sample-hop))
+ "Enrichment pattern should produce a valid hop object")
+ (is (spoon.spec/test-valid? ::hop.format/hop-wrapper
+ (hop.enrich/enrich-hop-wrapper hop.data/sample-hop-wrapper))
+ "Enrichment pattern should produce a valid hop object")
+ (is (spoon.spec/test-valid? ::hop.format/hops
+ (hop.enrich/enrich-hops hop.data/sample-hops))
+ "Enrichment pattern should produce a valid hop object")
+ (is (spoon.spec/test-valid? ::hop.format/hops-wrapper
+ (hop.enrich/enrich-hops-wrapper hop.data/sample-hops-wrapper))
+ "Enrichment pattern should produce a valid hop object")
+ (testing "Static data comparison for enrichment pattern functions"
+ (is (= {:amount 0.0638
+ :display-time "60.1 m"
+ :use "Boil"
+ :name "Goldings, East Kent"
+ :time 60.1
+ :display-amount "0.141 lb"
+ :notes "Great all purpose UK hop for ales, stouts, porters"
+ :alpha 5.0
+ :version 1}
+ (hop.enrich/enrich-hop hop.data/sample-hop))))))
+
+
+(deftest generative-enrichment-tests
+ (testing "Ensure enrichment pattern works against arbitrary hop"
+ (letfn [(gen-hop [] (hop.data/generate-hop))]
+ (is (spoon.spec/test-valid? ::hop.format/hop
+ (hop.enrich/enrich-display-amount (gen-hop)))
+ "enrich-display-amount is a function to and from common-beer-format.hopspec/hop")
+ (is (spoon.spec/test-valid? ::hop.format/hop
+ (hop.enrich/enrich-display-time (gen-hop)))
+ "enrich-display-time is a function to and from common-beer-format.hopspec/hop")))
+ (testing "Ensure enrichment pattern works against arbitrary hop wrappers"
+ (is (spoon.spec/test-valid? ::hop.format/hop-wrapper
+ (hop.enrich/enrich-hop-wrapper (hop.data/generate-hop-wrapper)))
+ "enrich-hop-wrapper is a function to and from common-beer-format.hopspec/hop-wrapper")
+ (is (spoon.spec/test-valid? ::hop.format/hops
+ (hop.enrich/enrich-hops (hop.data/generate-hops)))
+ "enrich-hops is a function to and from common-beer-format.hopspec/hops")
+ (is (spoon.spec/test-valid? ::hop.format/hops-wrapper
+ (hop.enrich/enrich-hops-wrapper (hop.data/generate-hops-wrapper)))
+ "enrich-hops-wrapper is a function to and from common-beer-format.hopspec/hops-wrapper")))
+
diff --git a/test/brewtility/enrich/impl_test.cljc b/test/brewtility/enrich/impl_test.cljc
new file mode 100644
index 0000000..2b060dc
--- /dev/null
+++ b/test/brewtility/enrich/impl_test.cljc
@@ -0,0 +1,895 @@
+(ns brewtility.enrich.impl-test
+ (:require #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ [brewtility.enrich.impl :as sut]
+ [brewtility.units.color :as color]
+ [brewtility.units.options :as options]
+ [brewtility.units.pressure :as pressure]
+ [brewtility.units.specific-gravity :as specific-gravity]
+ [brewtility.units.temperature :as temperature]
+ [brewtility.units.time :as time]
+ [brewtility.units.volume :as volume]
+ [brewtility.units.weight :as weight]
+ [clojure.set :as set]
+ [clojure.string :as str]))
+
+
+(deftest code-type-tests
+ (testing "Ensure maps used for options are structurally correct"
+ (testing "Defaults by System - These must be maps from Systems of Measure to their corresponding measurements."
+ (is (= (sort (keys sut/default-color-by-system))
+ (sort (keys sut/default-pressure-by-system))
+ (sort (keys sut/default-specific-gravity-by-system))
+ (sort (keys sut/default-temperature-by-system))
+ (sort (keys sut/default-time-by-system))
+ (sort (keys sut/default-volume-by-system))
+ (sort (keys sut/default-weight-by-system))
+ (sort (vec options/systems-of-measure))))
+ (is (set/subset? (set (vals sut/default-color-by-system)) color/measurements))
+ (is (set/subset? (set (vals sut/default-pressure-by-system)) pressure/measurements))
+ (is (set/subset? (set (vals sut/default-specific-gravity-by-system)) specific-gravity/measurements))
+ (is (set/subset? (set (vals sut/default-temperature-by-system)) temperature/measurements))
+ (is (set/subset? (set (vals sut/default-time-by-system)) time/measurements))
+ (is (set/subset? (set (vals sut/default-volume-by-system)) volume/measurements))
+ (is (set/subset? (set (vals sut/default-weight-by-system)) weight/measurements))))
+ (testing "BeerXML Standard Units"
+ (is (= (sort (keys sut/beer-xml-standard-units))
+ (sort (vec options/measurement-types))))
+ (is (contains? color/measurements (get sut/beer-xml-standard-units options/color)))
+ (is (contains? pressure/measurements (get sut/beer-xml-standard-units options/pressure)))
+ (is (contains? specific-gravity/measurements (get sut/beer-xml-standard-units options/specific-gravity)))
+ (is (contains? temperature/measurements (get sut/beer-xml-standard-units options/temperature)))
+ (is (contains? time/measurements (get sut/beer-xml-standard-units options/time)))
+ (is (contains? volume/measurements (get sut/beer-xml-standard-units options/volume)))
+ (is (contains? weight/measurements (get sut/beer-xml-standard-units options/weight))))
+ (testing "Option keys"
+ (is (keyword? sut/value-key))
+ (is (keyword? sut/low-value-key))
+ (is (keyword? sut/high-value-key))
+ (is (keyword? sut/display-key))
+ (is (keyword? sut/fine-grain-target-units))
+ (is (keyword? sut/fine-grain-precision))
+ (is (keyword? sut/fine-grain-suffix))))
+
+
+(deftest ->displayable-color-test
+ (testing "Ensure ->displayable-color supports its full suite of options."
+ (is (= "2.955 ebc"
+ (sut/->displayable-units options/color 1.5 options/srm options/ebc)
+ (sut/->displayable-units options/color 1.5 options/srm options/ebc sut/default-display-options))
+ "Conversion defaults to 3 digits of precisions and shorthand unit names")
+ (is (= "3.0 ebc"
+ (sut/->displayable-units options/color 1.5 options/srm options/ebc {options/precision 1})
+ (sut/->displayable-units options/color 1.5 options/srm options/ebc {options/precision 1
+ options/suffix options/short}))
+ "Conversion may override the default precision")
+ (is (= "1.668 degrees lovibond"
+ (sut/->displayable-units options/color 1.5 options/srm options/lovibond {options/suffix options/full})
+ (sut/->displayable-units options/color 1.5 options/srm options/lovibond {options/precision 3
+ options/suffix options/full}))
+ "Conversion may override the default suffix")))
+
+
+(deftest ->displayable-pressure-test
+ (testing "Ensure ->displayable-pressure supports its full suite of options"
+ (is (= "0.103 bar"
+ (sut/->displayable-units options/pressure 1.5 options/psi options/bar)
+ (sut/->displayable-units options/pressure 1.5 options/psi options/bar sut/default-display-options))
+ "Conversion defaults to 3 digits of precisions and shorthand unit names")
+ (is (= "0.1 bar"
+ (sut/->displayable-units options/pressure 1.5 options/psi options/bar {options/precision 1})
+ (sut/->displayable-units options/pressure 1.5 options/psi options/bar {options/precision 1
+ options/suffix options/short}))
+ "Conversion may override the default precision")
+ (is (= "10.342 kilopascals"
+ (sut/->displayable-units options/pressure 1.5 options/psi options/kilopascal {options/suffix options/full})
+ (sut/->displayable-units options/pressure 1.5 options/psi options/kilopascal {options/precision 3
+ options/suffix options/full}))
+ "Conversion may override the default suffix")))
+
+
+(deftest ->displayable-specific-gravity-test
+ (testing "Ensure ->displayable-specific-gravity supports its full suite of options"
+ (is (= "1.5 sg"
+ (sut/->displayable-units options/specific-gravity 1.5 options/specific-gravity options/specific-gravity)
+ (sut/->displayable-units options/specific-gravity 1.5 options/specific-gravity options/specific-gravity sut/default-display-options))
+ "Conversion defaults to 3 digits of precisions and shorthand unit names")
+ (is (= "1.5 sg"
+ (sut/->displayable-units options/specific-gravity 1.5 options/specific-gravity options/specific-gravity {options/precision 1})
+ (sut/->displayable-units options/specific-gravity 1.5 options/specific-gravity options/specific-gravity {options/precision 1
+ options/suffix options/short}))
+ "Conversion may override the default precision")
+ (is (= "1.5 specific gravity"
+ (sut/->displayable-units options/specific-gravity 1.5 options/specific-gravity options/specific-gravity {options/suffix options/full})
+ (sut/->displayable-units options/specific-gravity 1.5 options/specific-gravity options/specific-gravity {options/precision 3
+ options/suffix options/full}))
+ "Conversion may override the default suffix")))
+
+
+(deftest ->displayable-temperature-test
+ (testing "Ensure ->displayable-temperature supports its full suite of options"
+ (is (= "318.75 k"
+ (sut/->displayable-units options/temperature 45.6 options/c options/k)
+ (sut/->displayable-units options/temperature 45.6 options/c options/k {options/precision 3
+ options/suffix options/short}))
+ "Conversion defaults to 3 digits of precisions and shorthand unit names")
+ (is (= "318.8 k"
+ (sut/->displayable-units options/temperature 45.6 options/c options/k {options/precision 1})
+ (sut/->displayable-units options/temperature 45.6 options/c options/k {options/precision 1
+ options/suffix options/short}))
+ "Conversion may override the default precision")
+ (is (= "318.75 kelvin"
+ (sut/->displayable-units options/temperature 45.6 options/c options/k {options/precision 3
+ options/suffix options/full})
+ (sut/->displayable-units options/temperature 45.6 options/c options/k {options/suffix options/full}))
+ "Conversion may override the default suffix")))
+
+
+(deftest ->displayable-time-test
+ (testing "Ensure ->displayable-time supports its full suite of options"
+ (is (= "0.76 m"
+ (sut/->displayable-units options/time 45.6 options/second options/minute)
+ (sut/->displayable-units options/time 45.6 options/second options/minute {options/precision 3
+ options/suffix options/short}))
+ "Conversion defaults to 3 digits of precisions and shorthand unit names")
+ (is (= "0.8 m"
+ (sut/->displayable-units options/time 45.6 options/second options/minute {options/precision 1})
+ (sut/->displayable-units options/time 45.6 options/second options/minute {options/precision 1
+ options/suffix options/short}))
+ "Conversion may override the default precision")
+ (is (= "0.76 minute"
+ (sut/->displayable-units options/time 45.6 options/second options/minute {options/suffix options/full})
+ (sut/->displayable-units options/time 45.6 options/second options/minute {options/precision 3
+ options/suffix options/full}))
+ "Conversion may override the default suffix")))
+
+
+(deftest ->displayable-volume-test
+ (testing "Ensure ->displayable-volume supports its full suite of options"
+ (is (= "5.678 l"
+ (sut/->displayable-units options/volume 1.5 :american-gallon :liter)
+ (sut/->displayable-units options/volume 1.5 :american-gallon :liter {options/precision 3
+ options/suffix :short}))
+ "Conversion defaults to 3 digits of precisions and shorthand unit names")
+ (is (= "5.7 l"
+ (sut/->displayable-units options/volume 1.5 :american-gallon :liter {options/precision 1
+ options/suffix :short}))
+ "Conversion may override the default precision")
+ (is (= "5.678 liter"
+ (sut/->displayable-units options/volume 1.5 :american-gallon :liter {options/precision 3
+ options/suffix :full}))
+ "Conversion may override the default suffix"))
+ (testing "Ensure ->displayable-volume supports its full suite of options with static keys"
+ (is (= "5.678 l"
+ (sut/->displayable-units options/volume 1.5 options/american-gallon options/liter)
+ (sut/->displayable-units options/volume 1.5 options/american-gallon options/liter {options/precision options/default-precision
+ options/suffix options/short}))
+ "Conversion defaults to 3 digits of precisions and shorthand unit names with static keys")
+ (is (= "5.7 l"
+ (sut/->displayable-units options/volume 1.5 options/american-gallon options/liter {options/precision 1
+ options/suffix options/short}))
+ "Conversion may override the default precision with static keys")
+ (is (= "5.678 liter"
+ (sut/->displayable-units options/volume 1.5 options/american-gallon options/liter {options/precision 3
+ options/suffix options/full}))
+ "Conversion may override the default suffix with static keys")))
+
+
+(deftest ->displayable-weight-test
+ (testing "Ensure ->displayable-weight supports its full suite of options"
+ (is (= "0.053 oz"
+ (sut/->displayable-units options/weight 1.5 options/gram options/ounce)
+ (sut/->displayable-units options/weight 1.5 options/gram options/ounce sut/default-display-options))
+ "Conversion defaults to 3 digits of precisions and shorthand unit names")
+ (is (= "0.1 oz"
+ (sut/->displayable-units options/weight 1.5 options/gram options/ounce {options/precision 1})
+ (sut/->displayable-units options/weight 1.5 options/gram options/ounce {options/precision 1
+ options/suffix options/short}))
+ "Conversion may override the default precision")
+ (is (= "0.053 ounce"
+ (sut/->displayable-units options/weight 1.5 options/gram options/ounce {options/suffix options/full})
+ (sut/->displayable-units options/weight 1.5 options/gram options/ounce {options/precision 3
+ options/suffix options/full}))
+ "Conversion may override the default suffix")))
+
+
+(deftest target-unit-error-test
+ (testing "Ensure target-unit-error sets an appropriate error for color"
+ (let [error-map {:some "error"}
+ new-error-map (sut/target-unit-error error-map options/color :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :target-units)
+ "The new error is recorded")
+ (is (str/includes? (:target-units new-error-map) "color")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "lovibond")
+ "The valid units are included in the error message")))
+ (testing "Ensure target-unit-error sets an appropriate error for pressure"
+ (let [error-map {:some "error"}
+ new-error-map (sut/target-unit-error error-map options/pressure :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :target-units)
+ "The new error is recorded")
+ (is (str/includes? (:target-units new-error-map) "pressure")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "psi")
+ "The valid units are included in the error message")))
+ (testing "Ensure target-unit-error sets an appropriate error for specific-gravity"
+ (let [error-map {:some "error"}
+ new-error-map (sut/target-unit-error error-map options/specific-gravity :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :target-units)
+ "The new error is recorded")
+ (is (str/includes? (:target-units new-error-map) "specific-gravity")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "specific-gravity")
+ "The valid units are included in the error message")))
+ (testing "Ensure target-unit-error sets an appropriate error for temperature"
+ (let [error-map {:some "error"}
+ new-error-map (sut/target-unit-error error-map options/temperature :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :target-units)
+ "The new error is recorded")
+ (is (str/includes? (:target-units new-error-map) "temperature")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "celsius")
+ "The valid units are included in the error message")))
+ (testing "Ensure target-unit-error sets an appropriate error for time"
+ (let [error-map {:some "error"}
+ new-error-map (sut/target-unit-error error-map options/time :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :target-units)
+ "The new error is recorded")
+ (is (str/includes? (:target-units new-error-map) "time")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "minute")
+ "The valid units are included in the error message")))
+ (testing "Ensure target-unit-error sets an appropriate error for volume"
+ (let [error-map {:some "error"}
+ new-error-map (sut/target-unit-error error-map options/volume :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :target-units)
+ "The new error is recorded")
+ (is (str/includes? (:target-units new-error-map) "volume")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "teaspoon")
+ "The valid units are included in the error message")))
+ (testing "Ensure target-unit-error sets an appropriate error for weight"
+ (let [error-map {:some "error"}
+ new-error-map (sut/target-unit-error error-map options/weight :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :target-units)
+ "The new error is recorded")
+ (is (str/includes? (:target-units new-error-map) "weight")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:target-units new-error-map) "pound")
+ "The valid units are included in the error message"))))
+
+
+(deftest source-unit-error-test
+ (testing "Ensure source-unit-error sets an appropriate error for color"
+ (let [error-map {:some "error"}
+ new-error-map (sut/source-unit-error error-map options/color :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :source-units)
+ "The new error is recorded")
+ (is (str/includes? (:source-units new-error-map) "color")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "lovibond")
+ "The valid units are included in the error message")))
+ (testing "Ensure source-unit-error sets an appropriate error for pressure"
+ (let [error-map {:some "error"}
+ new-error-map (sut/source-unit-error error-map options/pressure :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :source-units)
+ "The new error is recorded")
+ (is (str/includes? (:source-units new-error-map) "pressure")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "psi")
+ "The valid units are included in the error message")))
+ (testing "Ensure source-unit-error sets an appropriate error for specific-gravity"
+ (let [error-map {:some "error"}
+ new-error-map (sut/source-unit-error error-map options/specific-gravity :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :source-units)
+ "The new error is recorded")
+ (is (str/includes? (:source-units new-error-map) "specific-gravity")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "specific-gravity")
+ "The valid units are included in the error message")))
+ (testing "Ensure source-unit-error sets an appropriate error for temperature"
+ (let [error-map {:some "error"}
+ new-error-map (sut/source-unit-error error-map options/temperature :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :source-units)
+ "The new error is recorded")
+ (is (str/includes? (:source-units new-error-map) "temperature")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "celsius")
+ "The valid units are included in the error message")))
+ (testing "Ensure source-unit-error sets an appropriate error for time"
+ (let [error-map {:some "error"}
+ new-error-map (sut/source-unit-error error-map options/time :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :source-units)
+ "The new error is recorded")
+ (is (str/includes? (:source-units new-error-map) "time")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "minute")
+ "The valid units are included in the error message")))
+ (testing "Ensure source-unit-error sets an appropriate error for volume"
+ (let [error-map {:some "error"}
+ new-error-map (sut/source-unit-error error-map options/volume :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :source-units)
+ "The new error is recorded")
+ (is (str/includes? (:source-units new-error-map) "volume")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "teaspoon")
+ "The valid units are included in the error message")))
+ (testing "Ensure source-unit-error sets an appropriate error for weight"
+ (let [error-map {:some "error"}
+ new-error-map (sut/source-unit-error error-map options/weight :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map :source-units)
+ "The new error is recorded")
+ (is (str/includes? (:source-units new-error-map) "weight")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "fake")
+ "The invalid unit is included in the error message")
+ (is (str/includes? (:source-units new-error-map) "pound")
+ "The valid units are included in the error message"))))
+
+
+(deftest systems-of-meaure-error-test
+ (testing "Ensure systems-of-meaure-error sets an appropriate error for color."
+ (let [error-map {:some "error"}
+ new-error-map (sut/systems-of-meaure-error error-map options/color :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/system-of-measure)
+ "The new error is recorded")
+ (is (str/includes? (options/system-of-measure new-error-map) "color")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "fake")
+ "The invalid system of measure is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "metric")
+ "The valid values are included in the error message")))
+ (testing "Ensure systems-of-meaure-error sets an appropriate error for pressure."
+ (let [error-map {:some "error"}
+ new-error-map (sut/systems-of-meaure-error error-map options/pressure :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/system-of-measure)
+ "The new error is recorded")
+ (is (str/includes? (options/system-of-measure new-error-map) "pressure")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "fake")
+ "The invalid system of measure is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "metric")
+ "The valid values are included in the error message")))
+ (testing "Ensure systems-of-meaure-error sets an appropriate error for specific-gravity."
+ (let [error-map {:some "error"}
+ new-error-map (sut/systems-of-meaure-error error-map options/specific-gravity :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/system-of-measure)
+ "The new error is recorded")
+ (is (str/includes? (options/system-of-measure new-error-map) "specific-gravity")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "fake")
+ "The invalid system of measure is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "metric")
+ "The valid values are included in the error message")))
+ (testing "Ensure systems-of-meaure-error sets an appropriate error for temperature."
+ (let [error-map {:some "error"}
+ new-error-map (sut/systems-of-meaure-error error-map options/temperature :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/system-of-measure)
+ "The new error is recorded")
+ (is (str/includes? (options/system-of-measure new-error-map) "temperature")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "fake")
+ "The invalid system of measure is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "metric")
+ "The valid values are included in the error message")))
+ (testing "Ensure systems-of-meaure-error sets an appropriate error for time."
+ (let [error-map {:some "error"}
+ new-error-map (sut/systems-of-meaure-error error-map options/time :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/system-of-measure)
+ "The new error is recorded")
+ (is (str/includes? (options/system-of-measure new-error-map) "time")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "fake")
+ "The invalid system of measure is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "metric")
+ "The valid values are included in the error message")))
+ (testing "Ensure systems-of-meaure-error sets an appropriate error for volume."
+ (let [error-map {:some "error"}
+ new-error-map (sut/systems-of-meaure-error error-map options/volume :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/system-of-measure)
+ "The new error is recorded")
+ (is (str/includes? (options/system-of-measure new-error-map) "volume")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "fake")
+ "The invalid system of measure is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "metric")
+ "The valid values are included in the error message")))
+ (testing "Ensure systems-of-meaure-error sets an appropriate error for weight."
+ (let [error-map {:some "error"}
+ new-error-map (sut/systems-of-meaure-error error-map options/weight :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/system-of-measure)
+ "The new error is recorded")
+ (is (str/includes? (options/system-of-measure new-error-map) "weight")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "fake")
+ "The invalid system of measure is included in the error message")
+ (is (str/includes? (options/system-of-measure new-error-map) "metric")
+ "The valid values are included in the error message"))))
+
+
+(deftest precision-error-test
+ (testing "Ensure precision-error sets an appropriate error"
+ (let [error-map {:some "error"}
+ new-error-map (sut/precision-error error-map options/volume 10)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/precision)
+ "The new error is recorded")
+ (is (str/includes? (options/precision new-error-map) "volume")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/precision new-error-map) "10")
+ "The invalid system of measure is included in the error message"))))
+
+
+(deftest suffix-error-test
+ (testing "Ensure suffix-error sets an appropriate error"
+ (let [error-map {:some "error"}
+ new-error-map (sut/suffix-error error-map options/volume :fake)]
+ (is (contains? new-error-map :some)
+ "Previously recorded errors are preserved")
+ (is (contains? new-error-map options/suffix)
+ "The new error is recorded")
+ (is (str/includes? (options/suffix new-error-map) "volume")
+ "The type of attempted conversion is included in the error message")
+ (is (str/includes? (options/suffix new-error-map) "fake")
+ "The invalid suffix type is included in the error message")
+ (is (str/includes? (options/suffix new-error-map) "full")
+ "The valid values are included in the error message"))))
+
+
+(deftest parse-enrich-displayable-color-opts-test
+ (let [valid-opts {:target-units options/lovibond
+ :source-units options/srm
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}
+ error-regex #"Invalid enrichment options for ->displayable-units:"]
+ (testing "Ensure parse-enrich-displayable-color-opts returns valid opts"
+ (is (= valid-opts (sut/parse-enrich-displayable-units-opts options/color valid-opts))
+ "Valid opts are returned unchanged"))
+ (testing "Ensure parse-enrich-displayable-temperature-opts returns valid opts with static keys"
+ (let [valid-opts-w-keys {:target-units options/lovibond
+ :source-units options/srm
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}]
+ (is (= valid-opts-w-keys (sut/parse-enrich-displayable-units-opts options/color valid-opts-w-keys))
+ "Valid opts are returned unchanged with static keys")))
+ (testing "Missing any option throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/color (dissoc valid-opts :target-units)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/color (dissoc valid-opts :target-units)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/color (dissoc valid-opts :source-units)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/color (dissoc valid-opts :source-units)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/color (dissoc valid-opts options/precision)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/color (dissoc valid-opts options/precision)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/color (dissoc valid-opts options/suffix)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/color (dissoc valid-opts options/suffix))))))
+ (testing "An invalid selection for any require value throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/color (assoc valid-opts :target-units :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/color (assoc valid-opts :target-units :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/color (assoc valid-opts :source-units :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/color (assoc valid-opts :source-units :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/color (assoc valid-opts options/precision :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/color (assoc valid-opts options/precision :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/color (assoc valid-opts options/suffix :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/color (assoc valid-opts options/suffix :fake))))))))
+
+
+(deftest parse-enrich-displayable-pressure-opts-test
+ (let [valid-opts {:target-units options/psi
+ :source-units options/kilopascal
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}
+ error-regex #"Invalid enrichment options for ->displayable-units:"]
+ (testing "Ensure parse-enrich-displayable-pressure-opts returns valid opts"
+ (is (= valid-opts (sut/parse-enrich-displayable-units-opts options/pressure valid-opts))
+ "Valid opts are returned unchanged"))
+ (testing "Ensure parse-enrich-displayable-pressure-opts returns valid opts with static keys"
+ (let [valid-opts-w-keys {:target-units options/psi
+ :source-units options/kilopascal
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}]
+ (is (= valid-opts-w-keys (sut/parse-enrich-displayable-units-opts options/pressure valid-opts-w-keys))
+ "Valid opts are returned unchanged with static keys")))
+ (testing "Missing any option throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/pressure (dissoc valid-opts :target-units)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/pressure (dissoc valid-opts :target-units)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/pressure (dissoc valid-opts options/system-of-measure)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/pressure (dissoc valid-opts options/system-of-measure)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/pressure (dissoc valid-opts options/precision)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/pressure (dissoc valid-opts options/precision)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/pressure (dissoc valid-opts options/suffix)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/pressure (dissoc valid-opts options/suffix))))))
+ (testing "An invalid selection for any require value throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/pressure (assoc valid-opts :target-units :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/pressure (assoc valid-opts :target-units :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/pressure (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/pressure (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/pressure (assoc valid-opts options/precision :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/pressure (assoc valid-opts options/precision :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/pressure (assoc valid-opts options/suffix :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/pressure (assoc valid-opts options/suffix :fake))))))))
+
+
+(deftest parse-enrich-displayable-specific-gravity-opts-test
+ (let [valid-opts {:target-units options/specific-gravity
+ :source-units options/specific-gravity
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}
+ error-regex #"Invalid enrichment options for ->displayable-units:"]
+ (testing "Ensure parse-enrich-displayable-specific-gravity-opts returns valid opts"
+ (is (= valid-opts (sut/parse-enrich-displayable-units-opts options/specific-gravity valid-opts))
+ "Valid opts are returned unchanged"))
+ (testing "Ensure parse-enrich-displayable-specific-gravity-opts returns valid opts with static keys"
+ (let [valid-opts-w-keys {:target-units options/specific-gravity
+ :source-units options/specific-gravity
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}]
+ (is (= valid-opts-w-keys (sut/parse-enrich-displayable-units-opts options/specific-gravity valid-opts-w-keys))
+ "Valid opts are returned unchanged with static keys")))
+ (testing "Missing any option throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (dissoc valid-opts :target-units)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (dissoc valid-opts :target-units)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (dissoc valid-opts options/system-of-measure)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (dissoc valid-opts options/system-of-measure)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (dissoc valid-opts options/precision)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (dissoc valid-opts options/precision)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (dissoc valid-opts options/suffix)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (dissoc valid-opts options/suffix))))))
+ (testing "An invalid selection for any require value throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (assoc valid-opts :target-units :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (assoc valid-opts :target-units :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (assoc valid-opts options/precision :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (assoc valid-opts options/precision :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (assoc valid-opts options/suffix :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/specific-gravity (assoc valid-opts options/suffix :fake))))))))
+
+
+(deftest parse-enrich-displayable-temperature-opts-test
+ (let [valid-opts {:target-units options/c
+ :source-units options/c
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}
+ error-regex #"Invalid enrichment options for ->displayable-units:"]
+ (testing "Ensure parse-enrich-displayable-temperature-opts returns valid opts"
+ (is (= valid-opts (sut/parse-enrich-displayable-units-opts options/temperature valid-opts))
+ "Valid opts are returned unchanged"))
+ (testing "Ensure parse-enrich-displayable-temperature-opts returns valid opts with static keys"
+ (let [valid-opts-w-keys {:target-units options/c
+ :source-units options/c
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}]
+ (is (= valid-opts-w-keys (sut/parse-enrich-displayable-units-opts options/temperature valid-opts-w-keys))
+ "Valid opts are returned unchanged with static keys")))
+ (testing "Missing any option throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/temperature (dissoc valid-opts :target-units)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/temperature (dissoc valid-opts :target-units)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/temperature (dissoc valid-opts options/system-of-measure)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/temperature (dissoc valid-opts options/system-of-measure)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/temperature (dissoc valid-opts options/precision)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/temperature (dissoc valid-opts options/precision)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/temperature (dissoc valid-opts options/suffix)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/temperature (dissoc valid-opts options/suffix))))))
+ (testing "An invalid selection for any require value throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/temperature (assoc valid-opts :target-units :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/temperature (assoc valid-opts :target-units :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/temperature (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/temperature (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/temperature (assoc valid-opts options/precision :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/temperature (assoc valid-opts options/precision :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/temperature (assoc valid-opts options/suffix :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/temperature (assoc valid-opts options/suffix :fake))))))))
+
+
+(deftest parse-enrich-displayable-time-opts-test
+ (let [valid-opts {:target-units options/minute
+ :source-units options/minute
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}
+ error-regex #"Invalid enrichment options for ->displayable-units:"]
+ (testing "Ensure parse-enrich-displayable-time-opts returns valid opts"
+ (is (= valid-opts (sut/parse-enrich-displayable-units-opts options/time valid-opts))
+ "Valid opts are returned unchanged"))
+ (testing "Ensure parse-enrich-displayable-temperature-opts returns valid opts with static keys"
+ (let [valid-opts-w-keys {:target-units options/minute
+ :source-units options/minute
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}]
+ (is (= valid-opts-w-keys (sut/parse-enrich-displayable-units-opts options/time valid-opts-w-keys))
+ "Valid opts are returned unchanged with static keys")))
+ (testing "Missing any option throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/time (dissoc valid-opts :target-units)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/time (dissoc valid-opts :target-units)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/time (dissoc valid-opts options/system-of-measure)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/time (dissoc valid-opts options/system-of-measure)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/time (dissoc valid-opts options/precision)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/time (dissoc valid-opts options/precision)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/time (dissoc valid-opts options/suffix)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/time (dissoc valid-opts options/suffix))))))
+ (testing "An invalid selection for any require value throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/time (assoc valid-opts :target-units :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/time (assoc valid-opts :target-units :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/time (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/time (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/time (assoc valid-opts options/precision :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/time (assoc valid-opts options/precision :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/time (assoc valid-opts options/suffix :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/time (assoc valid-opts options/suffix :fake))))))))
+
+
+(deftest parse-enrich-displayable-volume-opts-test
+ (let [valid-opts {:target-units options/teaspoon
+ :source-units options/litre
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}
+ error-regex #"Invalid enrichment options for ->displayable-units:"]
+ (testing "Ensure parse-enrich-displayable-volume-opts returns valid opts"
+ (is (= valid-opts (sut/parse-enrich-displayable-units-opts options/volume valid-opts))
+ "Valid opts are returned unchanged"))
+ (testing "Ensure parse-enrich-displayable-temperature-opts returns valid opts with static keys"
+ (let [valid-opts-w-keys {:target-units options/teaspoon
+ :source-units options/litre
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}]
+ (is (= valid-opts-w-keys (sut/parse-enrich-displayable-units-opts options/volume valid-opts-w-keys))
+ "Valid opts are returned unchanged with static keys")))
+ (testing "Missing any option throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/volume (dissoc valid-opts :target-units)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/volume (dissoc valid-opts :target-units)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/volume (dissoc valid-opts options/system-of-measure)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/volume (dissoc valid-opts options/system-of-measure)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/volume (dissoc valid-opts options/precision)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/volume (dissoc valid-opts options/precision)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/volume (dissoc valid-opts options/suffix)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/volume (dissoc valid-opts options/suffix))))))
+ (testing "An invalid selection for any require value throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/volume (assoc valid-opts :target-units :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/volume (assoc valid-opts :target-units :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/volume (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/volume (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/volume (assoc valid-opts options/precision :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/volume (assoc valid-opts options/precision :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/volume (assoc valid-opts options/suffix :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/volume (assoc valid-opts options/suffix :fake))))))))
+
+
+(deftest parse-enrich-displayable-weight-opts-test
+ (let [valid-opts {:target-units options/pound
+ :source-units options/kilogram
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}
+ error-regex #"Invalid enrichment options for ->displayable-units:"]
+ (testing "Ensure parse-enrich-displayable-weight-opts returns valid opts"
+ (is (= valid-opts (sut/parse-enrich-displayable-units-opts options/weight valid-opts))
+ "Valid opts are returned unchanged"))
+ (testing "Ensure parse-enrich-displayable-temperature-opts returns valid opts with static keys"
+ (let [valid-opts-w-keys {:target-units options/pound
+ :source-units options/kilogram
+ options/system-of-measure options/metric
+ options/precision 2
+ options/suffix options/full}]
+ (is (= valid-opts-w-keys (sut/parse-enrich-displayable-units-opts options/weight valid-opts-w-keys))
+ "Valid opts are returned unchanged with static keys")))
+ (testing "Missing any option throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/weight (dissoc valid-opts :target-units)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/weight (dissoc valid-opts :target-units)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/weight (dissoc valid-opts options/system-of-measure)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/weight (dissoc valid-opts options/system-of-measure)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/weight (dissoc valid-opts options/precision)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/weight (dissoc valid-opts options/precision)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/weight (dissoc valid-opts options/suffix)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/weight (dissoc valid-opts options/suffix))))))
+ (testing "An invalid selection for any require value throws an error"
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/weight (assoc valid-opts :target-units :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/weight (assoc valid-opts :target-units :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/weight (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/weight (assoc valid-opts options/system-of-measure :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/weight (assoc valid-opts options/precision :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/weight (assoc valid-opts options/precision :fake)))))
+ #?(:clj (is (thrown-with-msg? Exception error-regex (sut/parse-enrich-displayable-units-opts options/weight (assoc valid-opts options/suffix :fake)))))
+ #?(:cljs (is (thrown-with-msg? js/Error error-regex (sut/parse-enrich-displayable-units-opts options/weight (assoc valid-opts options/suffix :fake))))))))
+
+
+(deftest enrich-displayable-color-test
+ (testing "Validate displayable color enrichment."
+ (testing "If no value is provided, return the original map."
+ (let [base-map {:hello "there"}]
+ (is (= base-map (sut/enrich-displayable-units options/color base-map {sut/display-key :hello
+ sut/value-key :missing})))))
+ (testing "When a value is provided, add the data at `:display-key`"
+ (let [base-map {:hello "there"
+ :value 1}
+ result-map (assoc base-map :display "0.595 srm")]
+ (is (= result-map (sut/enrich-displayable-units options/color base-map {sut/display-key :display
+ sut/value-key :value
+ :source-units options/lovibond
+ :target-units options/srm})))))))
+
+
+(deftest enrich-displayable-pressure-test
+ (testing "Validate displayable pressure enrichment."
+ (testing "If no value is provided, return the original map."
+ (let [base-map {:hello "there"}]
+ (is (= base-map (sut/enrich-displayable-units options/pressure base-map {sut/display-key :hello
+ sut/value-key :missing})))))
+ (testing "When a value is provided, add the data at `:display-key`"
+ (let [base-map {:hello "there"
+ :value 1}
+ result-map (assoc base-map :display "1000.0 pa")]
+ (is (= result-map (sut/enrich-displayable-units options/pressure base-map {sut/display-key :display
+ sut/value-key :value
+ sut/fine-grain-target-units options/pascal})))))))
+
+
+(deftest enrich-displayable-specific-gravity-test
+ (testing "Validate displayable specific-gravity enrichment."
+ (testing "If no value is provided, return the original map."
+ (let [base-map {:hello "there"}]
+ (is (= base-map (sut/enrich-displayable-units options/specific-gravity base-map {sut/display-key :hello
+ sut/value-key :missing})))))
+ (testing "When a value is provided, add the data at `:display-key`"
+ (let [base-map {:hello "there"
+ :value 1}
+ result-map (assoc base-map :display "1.0 sg")]
+ (is (= result-map (sut/enrich-displayable-units options/specific-gravity base-map {sut/display-key :display
+ sut/value-key :value
+ sut/fine-grain-target-units options/specific-gravity})))))))
+
+
+(deftest enrich-displayable-temperature-test
+ (testing "Validate displayable temperature enrichment."
+ (testing "If no value is provided, return the original map."
+ (let [base-map {:hello "there"}]
+ (is (= base-map (sut/enrich-displayable-units options/temperature base-map {sut/display-key :hello
+ sut/value-key :missing})))))
+ (testing "When a value is provided, add the data at `:display-key`"
+ (let [base-map {:hello "there"
+ :value 1}
+ result-map (assoc base-map :display "274.15 k")]
+ (is (= result-map (sut/enrich-displayable-units options/temperature base-map {sut/display-key :display
+ sut/value-key :value
+ sut/fine-grain-target-units options/k})))))))
+
+
+(deftest enrich-displayable-time-test
+ (testing "Validate displayable time enrichment."
+ (testing "If no value is provided, return the original map."
+ (let [base-map {:hello "there"}]
+ (is (= base-map (sut/enrich-displayable-units options/time base-map {sut/display-key :hello
+ sut/value-key :missing})))))
+ (testing "When a value is provided, add the data at `:display-key`"
+ (let [base-map {:hello "there"
+ :value 1}
+ result-map (assoc base-map :display "1.0 m")]
+ (is (= result-map (sut/enrich-displayable-units options/time base-map {sut/display-key :display
+ sut/value-key :value
+ sut/fine-grain-target-units options/minute})))))))
+
+
+(deftest enrich-displayable-volume-test
+ (testing "Validate displayable volume enrichment."
+ (testing "If no value is provided, return the original map."
+ (let [base-map {:hello "there"}]
+ (is (= base-map (sut/enrich-displayable-units options/volume base-map {sut/display-key :hello
+ sut/value-key :missing})))))
+ (testing "When a value is provided, add the data at `:display-key`"
+ (let [base-map {:hello "there"
+ :value 1}
+ result-map (assoc base-map :display "202.884 tsp")]
+ (is (= result-map (sut/enrich-displayable-units options/volume base-map {sut/display-key :display
+ sut/value-key :value
+ sut/fine-grain-target-units options/teaspoon})))))))
+
+
+(deftest enrich-displayable-weight-test
+ (testing "Validate displayable weight enrichment."
+ (testing "If no value is provided, return the original map."
+ (let [base-map {:hello "there"}]
+ (is (= base-map (sut/enrich-displayable-units options/weight base-map {sut/display-key :hello
+ sut/value-key :missing})))))
+ (testing "When a value is provided, add the data at `:display-key`"
+ (let [base-map {:hello "there"
+ :value 1}
+ result-map (assoc base-map :display "2.205 lb")]
+ (is (= result-map (sut/enrich-displayable-units options/weight base-map {sut/display-key :display
+ sut/value-key :value
+ sut/fine-grain-target-units options/pound})))))))
+
+
+(deftest enrich-displayable-range-test
+ (testing "Validate displayable range enrichment."
+ (testing "If neither value is provided, return the original map."
+ (let [base-map {:a 1
+ :b 3}]
+ (is (= base-map (sut/enrich-displayable-range options/weight base-map {sut/display-key :hello
+ sut/low-value-key :missing
+ sut/high-value-key :also-gone})))))
+ (testing "When all values are provided, add the data at `:display-key`"
+ (let [base-map {:a 3
+ :b 6}
+ result-map (assoc base-map :display "6.614 - 13.228 lb")]
+ (is (= result-map (sut/enrich-displayable-range options/weight base-map {sut/display-key :display
+ sut/low-value-key :a
+ sut/high-value-key :b
+ sut/fine-grain-target-units options/pound})))))))
diff --git a/test/brewtility/enrich/mash_test.cljc b/test/brewtility/enrich/mash_test.cljc
new file mode 100644
index 0000000..e8b6356
--- /dev/null
+++ b/test/brewtility/enrich/mash_test.cljc
@@ -0,0 +1,109 @@
+(ns brewtility.enrich.mash-test
+ (:require [brewtility.data.mash :as mash.data]
+ [brewtility.enrich.mash :as mash.enrich]
+ [com.wallbrew.spoon.spec :as spoon.spec]
+ [common-beer-format.mash :as mash.format]
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+
+
+(deftest static-enrichment-tests
+ (testing "Ensure enrichment pattern works against the static test mash steps"
+ (is (spoon.spec/test-valid? ::mash.format/mash-step
+ (mash.enrich/enrich-display-step-temperature mash.data/sample-mash-step))
+ "enrich-display-step-temperature is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash-step
+ (mash.enrich/enrich-display-infuse-amount mash.data/sample-mash-step))
+ "enrich-display-infuse-amount is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash-step
+ (mash.enrich/enrich-mash-step mash.data/sample-mash-step))
+ "enrich-mash-step is a function to and from common-beer-format.mash/mash"))
+ (testing "Ensure enrichment pattern works against static test mash step wrappers"
+ (is (spoon.spec/test-valid? ::mash.format/mash-step-wrapper
+ (mash.enrich/enrich-mash-step-wrapper mash.data/sample-mash-step-wrapper))
+ "enrich-mash-step-wrapper is a function to and from common-beer-format.mash/mash-step-wrapper"))
+ (testing "Ensure enrichment pattern works against static test mash steps"
+ (is (spoon.spec/test-valid? ::mash.format/mash-steps
+ (mash.enrich/enrich-mash-steps mash.data/sample-mash-steps))
+ "enrich-mash-steps is a function to and from common-beer-format.mash/mash-steps"))
+ (testing "Ensure enrichment pattern works against static test mash steps wrapper"
+ (is (spoon.spec/test-valid? ::mash.format/mash-steps
+ (:mash-steps (mash.enrich/enrich-mash-steps-wrapper mash.data/sample-mash-steps-wrapper)))
+ "enrich-mash-steps-wrapper is a function to and from common-beer-format.mash/mash-steps-wrapper"))
+ (testing "Ensure enrichment pattern works against static test mash"
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-display-grain-temperature mash.data/sample-mash))
+ "enrich-display-grain-temperature is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-display-tun-temperature mash.data/sample-mash))
+ "enrich-display-tun-temperature is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-display-sparge-temperature mash.data/sample-mash))
+ "enrich-display-sparge-temperature is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-display-tun-weight mash.data/sample-mash))
+ "enrich-display-tun-weight is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-mash mash.data/sample-mash))
+ "enrich-mash is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash-wrapper
+ (mash.enrich/enrich-mash-wrapper mash.data/sample-mash-wrapper))
+ "enrich-mash-wrapper is a function to and from common-beer-format.mash/mash-wrapper"))
+ (testing "Static data comparison for enrichment pattern functions"
+ (is (= {:name "Single Step Infusion, 68 C"
+ :version 1
+ :grain-temp 22.0
+ :mash-steps [{:mash-step {:name "Conversion Step, 68C"
+ :version 1
+ :type "Infusion"
+ :step-temp 68.0
+ :step-time 60.0
+ :infuse-amount 10.0
+ :display-step-temp "154.4 f"
+ :display-infuse-amt "2.642 gal"}}]
+ :display-grain-temp "71.6 f"}
+ (mash.enrich/enrich-mash mash.data/sample-mash)))))
+
+
+(deftest generative-enrichment-tests
+ (testing "Ensure enrichment pattern works against arbitrary mash steps"
+ (is (spoon.spec/test-valid? ::mash.format/mash-step
+ (mash.enrich/enrich-display-step-temperature (mash.data/generate-mash-step)))
+ "enrich-display-step-temperature is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash-step
+ (mash.enrich/enrich-display-infuse-amount (mash.data/generate-mash-step)))
+ "enrich-display-infuse-amount is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash-step
+ (mash.enrich/enrich-mash-step (mash.data/generate-mash-step)))
+ "enrich-mash-step is a function to and from common-beer-format.mash/mash"))
+ (testing "Ensure enrichment pattern works against arbitrary mash step wrappers"
+ (is (spoon.spec/test-valid? ::mash.format/mash-step-wrapper
+ (mash.enrich/enrich-mash-step-wrapper (mash.data/generate-mash-step-wrapper)))
+ "enrich-mash-step-wrapper is a function to and from common-beer-format.mash/mash-step-wrapper"))
+ (testing "Ensure enrichment pattern works against arbitrary mash steps"
+ (is (spoon.spec/test-valid? ::mash.format/mash-steps
+ (mash.enrich/enrich-mash-steps (mash.data/generate-mash-steps)))
+ "enrich-mash-steps is a function to and from common-beer-format.mash/mash-steps"))
+ (testing "Ensure enrichment pattern works against arbitrary mash steps wrapper"
+ (is (spoon.spec/test-valid? ::mash.format/mash-steps
+ (:mash-steps (mash.enrich/enrich-mash-steps-wrapper (mash.data/generate-mash-steps-wrapper))))
+ "enrich-mash-steps-wrapper is a function to and from common-beer-format.mash/mash-steps-wrapper"))
+ (testing "Ensure enrichment pattern works against arbitrary mash"
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-display-grain-temperature (mash.data/generate-mash)))
+ "enrich-display-grain-temperature is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-display-tun-temperature (mash.data/generate-mash)))
+ "enrich-display-tun-temperature is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-display-sparge-temperature (mash.data/generate-mash)))
+ "enrich-display-sparge-temperature is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-display-tun-weight (mash.data/generate-mash)))
+ "enrich-display-tun-weight is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash
+ (mash.enrich/enrich-mash (mash.data/generate-mash)))
+ "enrich-mash is a function to and from common-beer-format.mash/mash")
+ (is (spoon.spec/test-valid? ::mash.format/mash-wrapper
+ (mash.enrich/enrich-mash-wrapper (mash.data/generate-mash-wrapper)))
+ "enrich-mash-wrapper is a function to and from common-beer-format.mash/mash-wrapper")))
diff --git a/test/brewtility/enrich/miscs_test.cljc b/test/brewtility/enrich/miscs_test.cljc
new file mode 100644
index 0000000..d62c3f3
--- /dev/null
+++ b/test/brewtility/enrich/miscs_test.cljc
@@ -0,0 +1,245 @@
+(ns brewtility.enrich.miscs-test
+ (:require [brewtility.data.miscs :as miscs.data]
+ [brewtility.enrich.miscs :as miscs.enrich]
+ [com.wallbrew.spoon.spec :as spoon.spec]
+ [common-beer-format.miscs :as miscs.format]
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+
+
+(deftest enrich-amount-is-weight-test
+ (testing "Ensure enricher doesn't alter the value of existing `:amount is weight` keys"
+ (is (nil? (:amount-is-weight miscs.data/sample-misc))
+ "miscs.data/sample-misc does not set `amount-is-weight`")
+ (is (false? (-> miscs.data/sample-misc
+ miscs.enrich/enrich-amount-is-weight
+ :amount-is-weight))
+ "miscs.data/sample-misc does not set `amount-is-weight`, so the enricher sets the value to false")
+ (is (false? (-> miscs.data/sample-misc
+ (assoc :amount-is-weight false)
+ miscs.enrich/enrich-amount-is-weight
+ :amount-is-weight))
+ "Explicitly setting `:amount-is-weight` to false causes the value to be retained")
+ (is (true? (-> miscs.data/sample-misc
+ (assoc :amount-is-weight true)
+ miscs.enrich/enrich-amount-is-weight
+ :amount-is-weight))
+ "Explicitly setting `:amount-is-weight` to false causes the value to be retained"))
+ (testing "The two-arity version of `enrich-amount0is0-weight` has no behavioral differences"
+ (is (false? (-> miscs.data/sample-misc
+ (miscs.enrich/enrich-amount-is-weight :some-value)
+ :amount-is-weight))
+ "miscs.data/sample-misc does not set `amount-is-weight`, so the enricher sets the value to false")
+ (is (false? (-> miscs.data/sample-misc
+ (assoc :amount-is-weight false)
+ (miscs.enrich/enrich-amount-is-weight :some-value)
+ :amount-is-weight))
+ "Explicitly setting `:amount-is-weight` to false causes the value to be retained")
+ (is (true? (-> miscs.data/sample-misc
+ (assoc :amount-is-weight true)
+ (miscs.enrich/enrich-amount-is-weight :some-value)
+ :amount-is-weight))
+ "Explicitly setting `:amount-is-weight` to false causes the value to be retained")))
+
+
+(deftest enrich-display-time-test
+ (testing "Ensure enricher correctly defaults to setting display time"
+ (is (= "15.555 m" (-> miscs.data/sample-misc
+ (assoc :time 15.555)
+ miscs.enrich/enrich-display-time
+ :display-time))
+ "enrich-display-time defaults precision to 3")
+ (is (= "15.56 m" (-> miscs.data/sample-misc
+ (assoc :time 15.555)
+ (miscs.enrich/enrich-display-time {:misc-time-precision 2})
+ :display-time))
+ "enrich-display-time can be configured to use a different precision")
+ (is (= "13.2 s" (-> miscs.data/sample-misc
+ (assoc :time 0.22)
+ (miscs.enrich/enrich-display-time {:misc-time-target-units :second})
+ :display-time))
+ "enrich-display-time unites can be configured to use seconds")
+ (is (= "15.1 minute" (-> miscs.data/sample-misc
+ (assoc :time 15.1)
+ (miscs.enrich/enrich-display-time {:misc-time-suffix :full})
+ :display-time))
+ "enrich-display-time can be configured to use full suffixes")
+ (is (= "15.56 m" (-> miscs.data/sample-misc
+ (assoc :time 15.555)
+ (miscs.enrich/enrich-display-time {:precision 2})
+ :display-time))
+ "enrich-display-time can be configured to use a different precision with default settings keys")
+ (is (= "15.1 m" (-> miscs.data/sample-misc
+ (assoc :time 15.1)
+ (miscs.enrich/enrich-display-time {:system-of-measure :metric})
+ :display-time))
+ "enrich-display-time unites can be configured with default settings keys")
+ (is (= "15.1 minute" (-> miscs.data/sample-misc
+ (assoc :time 15.1)
+ (miscs.enrich/enrich-display-time {:suffix :full})
+ :display-time))
+ "enrich-display-time can be configured to use full suffixes with default settings keys"))
+ (testing "Ensure resulting `misc` still conforms to the spec"
+ (is (spoon.spec/test-valid? ::miscs.format/misc (-> miscs.data/sample-misc miscs.enrich/enrich-display-time))
+ "miscs.data/sample-misc conforms to the spec")))
+
+
+(deftest enrich-display-amount-test
+ (testing "Ensure enricher correctly defaults to setting display amount as a weight"
+ (let [weighted-misc (assoc miscs.data/sample-misc :amount-is-weight true)]
+ (is (= "0.022 lb" (-> weighted-misc
+ miscs.enrich/enrich-display-amount
+ :display-amount))
+ "miscs.data/sample-misc sets the amount to 15.0, which is the default unit")
+ (is (= "34.293 lb" (-> weighted-misc
+ (assoc :amount 15.555)
+ miscs.enrich/enrich-display-amount
+ :display-amount))
+ "enrich-display-amount defaults precision to 3")
+ (is (= "34.29 lb" (-> weighted-misc
+ (assoc :amount 15.555)
+ (miscs.enrich/enrich-display-amount {:misc-amount-precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision")
+ (is (= "15444.4 g" (-> weighted-misc
+ (assoc :amount 15.4444)
+ (miscs.enrich/enrich-display-amount {:misc-amount-target-units :gram})
+ :display-amount))
+ "enrich-display-amount unites can be configured to use seconds")
+ (is (= "33.069 pound" (-> weighted-misc
+ (assoc :amount 15.0)
+ (miscs.enrich/enrich-display-amount {:misc-amount-suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes")
+ (is (= "34.29 lb" (-> weighted-misc
+ (assoc :amount 15.555)
+ (miscs.enrich/enrich-display-amount {:precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision with default settings keys")
+ (is (= "15.4 kg" (-> weighted-misc
+ (assoc :amount 15.4)
+ (miscs.enrich/enrich-display-amount {:system-of-measure :metric})
+ :display-amount))
+ "enrich-display-amount unites can be configured with default settings keys")
+ (is (= "33.069 pound" (-> weighted-misc
+ (assoc :amount 15.0)
+ (miscs.enrich/enrich-display-amount {:suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes with default settings keys")))
+ (testing "Ensure enricher correctly defaults to setting display amount as a volume"
+ (let [volume-misc (assoc miscs.data/sample-misc :amount-is-weight false)]
+ (is (= "0.003 gal" (-> volume-misc
+ miscs.enrich/enrich-display-amount
+ :display-amount))
+ "miscs.data/sample-misc sets the amount to 15.0, which is the default unit")
+ (is (= "4.109 gal" (-> volume-misc
+ (assoc :amount 15.555)
+ miscs.enrich/enrich-display-amount
+ :display-amount))
+ "enrich-display-amount defaults precision to 3")
+ (is (= "4.11 gal" (-> volume-misc
+ (assoc :amount 15.555)
+ (miscs.enrich/enrich-display-amount {:misc-amount-precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision")
+ (is (= "3043.263 tsp" (-> volume-misc
+ (assoc :amount 15.0)
+ (miscs.enrich/enrich-display-amount {:misc-amount-target-units :teaspoon})
+ :display-amount))
+ "enrich-display-amount unites can be configured to use seconds")
+ (is (= "3.963 US gallon" (-> volume-misc
+ (assoc :amount 15.0)
+ (miscs.enrich/enrich-display-amount {:misc-amount-suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes")
+ (is (= "4.11 gal" (-> volume-misc
+ (assoc :amount 15.555)
+ (miscs.enrich/enrich-display-amount {:precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision with default settings keys")
+ (is (= "15.1 l" (-> volume-misc
+ (assoc :amount 15.1)
+ (miscs.enrich/enrich-display-amount {:system-of-measure :metric})
+ :display-amount))
+ "enrich-display-amount unites can be configured with default settings keys")
+ (is (= "3.963 US gallon" (-> volume-misc
+ (assoc :amount 15.0)
+ (miscs.enrich/enrich-display-amount {:suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes with default settings keys")))
+ (testing "Ensure resulting `misc` still conforms to the spec"
+ (is (spoon.spec/test-valid? ::miscs.format/misc (-> miscs.data/sample-misc
+ (assoc :amount-is-weight true)
+ miscs.enrich/enrich-display-amount))
+ "miscs.data/sample-misc conforms to the spec if the amount is a weight")
+ (is (spoon.spec/test-valid? ::miscs.format/misc (-> miscs.data/sample-misc
+ (assoc :amount-is-weight false)
+ miscs.enrich/enrich-display-amount))
+ "miscs.data/sample-misc conforms to the spec if the amount is a volume")
+ (is (spoon.spec/test-valid? ::miscs.format/misc (-> (miscs.data/generate-misc)
+ (assoc :amount-is-weight true)
+ miscs.enrich/enrich-display-amount))
+ "miscs.data/sample-misc conforms to the spec if the amount is a weight")
+ (is (spoon.spec/test-valid? ::miscs.format/misc (-> (miscs.data/generate-misc)
+ (assoc :amount-is-weight false)
+ miscs.enrich/enrich-display-amount))
+ "miscs.data/sample-misc conforms to the spec if the amount is a volume")))
+
+
+;;
+;; Whole object enrichment tests
+;;
+
+(deftest enrich-misc-tests
+ (testing "Ensure enrichment pattern functions generate conforming data"
+ (is (spoon.spec/test-valid? ::miscs.format/misc
+ (miscs.enrich/enrich-misc miscs.data/sample-misc))
+ "Enrichment pattern should produce a valid misc object")
+ (is (spoon.spec/test-valid? ::miscs.format/misc-wrapper
+ (miscs.enrich/enrich-misc-wrapper miscs.data/sample-misc-wrapper))
+ "Enrichment pattern should produce a valid misc object")
+ (is (spoon.spec/test-valid? ::miscs.format/miscs
+ (miscs.enrich/enrich-miscs miscs.data/sample-miscs))
+ "Enrichment pattern should produce a valid misc object")
+ (is (spoon.spec/test-valid? ::miscs.format/miscs-wrapper
+ (miscs.enrich/enrich-miscs-wrapper miscs.data/sample-miscs-wrapper))
+ "Enrichment pattern should produce a valid misc object")
+ (testing "Static data comparison for enrichment pattern functions"
+ (is (= {:amount 0.01
+ :display-time "15.1 m"
+ :amount-is-weight false
+ :use "Boil"
+ :name "Irish Moss"
+ :time 15.1
+ :type "Fining"
+ :notes "Used as a clarifying agent during the last few minutes of the boil"
+ :display-amount "0.003 gal"
+ :version 1}
+ (miscs.enrich/enrich-misc miscs.data/sample-misc))))))
+
+
+(deftest generative-enrichment-tests
+ (testing "Ensure enrichment pattern works against arbitrary misc"
+ (letfn [(gen-misc [] (miscs.data/generate-misc))]
+ (is (spoon.spec/test-valid? ::miscs.format/misc
+ (miscs.enrich/enrich-amount-is-weight (gen-misc)))
+ "enrich-amount-is-weight is a function to and from common-beer-format.misc/misc")
+ (is (spoon.spec/test-valid? ::miscs.format/misc
+ (miscs.enrich/enrich-display-time (gen-misc)))
+ "enrich-display-time is a function to and from common-beer-format.misc/misc")
+ (is (spoon.spec/test-valid? ::miscs.format/misc
+ (miscs.enrich/enrich-display-amount (gen-misc)))
+ "enrich-display-amount is a function to and from common-beer-format.misc/misc")
+ (is (spoon.spec/test-valid? ::miscs.format/misc
+ (miscs.enrich/enrich-misc (gen-misc)))
+ "enrich-misc is a function to and from common-beer-format.misc/misc")))
+ (testing "Ensure enrichment pattern works against arbitrary misc wrappers"
+ (is (spoon.spec/test-valid? ::miscs.format/misc-wrapper
+ (miscs.enrich/enrich-misc-wrapper (miscs.data/generate-misc-wrapper)))
+ "enrich-misc-wrapper is a function to and from common-beer-format.misc/misc-wrapper")
+ (is (spoon.spec/test-valid? ::miscs.format/miscs
+ (miscs.enrich/enrich-miscs (miscs.data/generate-miscs)))
+ "enrich-miscs is a function to and from common-beer-format.misc/miscs")
+ (is (spoon.spec/test-valid? ::miscs.format/miscs-wrapper
+ (miscs.enrich/enrich-miscs-wrapper (miscs.data/generate-miscs-wrapper)))
+ "enrich-miscs-wrapper is a function to and from common-beer-format.misc/miscs-wrapper")))
diff --git a/test/brewtility/enrich/waters_test.cljc b/test/brewtility/enrich/waters_test.cljc
new file mode 100644
index 0000000..1d6b0c8
--- /dev/null
+++ b/test/brewtility/enrich/waters_test.cljc
@@ -0,0 +1,105 @@
+(ns brewtility.enrich.waters-test
+ (:require [brewtility.data.waters :as waters.data]
+ [brewtility.enrich.waters :as waters.enrich]
+ [com.wallbrew.spoon.spec :as spoon.spec]
+ [common-beer-format.waters :as waters.format]
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+
+
+(deftest enrich-display-amount-test
+ (testing "Ensure :display-amount renders correctly"
+ (is (= "5.283 gal" (-> waters.data/sample-water
+ waters.enrich/enrich-display-amount
+ :display-amount))
+ "waters.data/sample-water sets the amount to 15.0, which is the default unit")
+ (is (= "4.109 gal" (-> waters.data/sample-water
+ (assoc :amount 15.555)
+ waters.enrich/enrich-display-amount
+ :display-amount))
+ "enrich-display-amount defaults precision to 3")
+ (is (= "4.11 gal" (-> waters.data/sample-water
+ (assoc :amount 15.555)
+ (waters.enrich/enrich-display-amount {:water-amount-precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision")
+ (is (= "3043.263 tsp" (-> waters.data/sample-water
+ (assoc :amount 15.0)
+ (waters.enrich/enrich-display-amount {:water-amount-target-units :teaspoon})
+ :display-amount))
+ "enrich-display-amount unites can be configured to use seconds")
+ (is (= "3.963 US gallon" (-> waters.data/sample-water
+ (assoc :amount 15.0)
+ (waters.enrich/enrich-display-amount {:water-amount-suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes")
+ (is (= "4.11 gal" (-> waters.data/sample-water
+ (assoc :amount 15.555)
+ (waters.enrich/enrich-display-amount {:precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision with default settings keys")
+ (is (= "15.1 l" (-> waters.data/sample-water
+ (assoc :amount 15.1)
+ (waters.enrich/enrich-display-amount {:system-of-measure :metric})
+ :display-amount))
+ "enrich-display-amount unites can be configured with default settings keys")
+ (is (= "3.963 US gallon" (-> waters.data/sample-water
+ (assoc :amount 15.0)
+ (waters.enrich/enrich-display-amount {:suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes with default settings keys")))
+
+
+;;
+;; Whole object enrichment tests
+;;
+
+(deftest enrich-water-tests
+ (testing "Ensure enrichment pattern functions generate conforming data"
+ (is (spoon.spec/test-valid? ::waters.format/water
+ (waters.enrich/enrich-water waters.data/sample-water))
+ "Enrichment pattern should produce a valid water object")
+ (is (spoon.spec/test-valid? ::waters.format/water-wrapper
+ (waters.enrich/enrich-water-wrapper waters.data/sample-water-wrapper))
+ "Enrichment pattern should produce a valid water object")
+ (is (spoon.spec/test-valid? ::waters.format/waters
+ (waters.enrich/enrich-waters waters.data/sample-waters))
+ "Enrichment pattern should produce a valid water object")
+ (is (spoon.spec/test-valid? ::waters.format/waters-wrapper
+ (waters.enrich/enrich-waters-wrapper waters.data/sample-waters-wrapper))
+ "Enrichment pattern should produce a valid water object")
+ (testing "Static data comparison for enrichment pattern functions"
+ (is (= {:amount 20.0
+ :name "Chicago"
+ :sulfate 725.0
+ :magnesium 45.0
+ :calcium 295.0
+ :bicarbonate 300.0
+ :display-amount "5.283 gal"
+ :notes "The best there is"
+ :sodium 55.0
+ :ph 8.0
+ :chloride 25.0
+ :version 1}
+ (waters.enrich/enrich-water waters.data/sample-water))))))
+
+
+(deftest generative-enrichment-tests
+ (testing "Ensure enrichment pattern works against arbitrary water"
+ (letfn [(gen-water [] (waters.data/generate-water))]
+ (is (spoon.spec/test-valid? ::waters.format/water
+ (waters.enrich/enrich-display-amount (gen-water)))
+ "enrich-display-amount is a function to and from common-beer-format.water/water")
+ (is (spoon.spec/test-valid? ::waters.format/water
+ (waters.enrich/enrich-water (gen-water)))
+ "enrich-water is a function to and from common-beer-format.water/water")))
+ (testing "Ensure enrichment pattern works against arbitrary water wrappers"
+ (is (spoon.spec/test-valid? ::waters.format/water-wrapper
+ (waters.enrich/enrich-water-wrapper (waters.data/generate-water-wrapper)))
+ "enrich-water-wrapper is a function to and from common-beer-format.water/water-wrapper")
+ (is (spoon.spec/test-valid? ::waters.format/waters
+ (waters.enrich/enrich-waters (waters.data/generate-waters)))
+ "enrich-waters is a function to and from common-beer-format.water/waters")
+ (is (spoon.spec/test-valid? ::waters.format/waters-wrapper
+ (waters.enrich/enrich-waters-wrapper (waters.data/generate-waters-wrapper)))
+ "enrich-waters-wrapper is a function to and from common-beer-format.water/waters-wrapper")))
diff --git a/test/brewtility/enrich/yeasts_test.cljc b/test/brewtility/enrich/yeasts_test.cljc
new file mode 100644
index 0000000..363aed7
--- /dev/null
+++ b/test/brewtility/enrich/yeasts_test.cljc
@@ -0,0 +1,221 @@
+(ns brewtility.enrich.yeasts-test
+ (:require [brewtility.data.yeasts :as yeasts.data]
+ [brewtility.enrich.yeasts :as yeasts.enrich]
+ [com.wallbrew.spoon.spec :as spoon.spec]
+ [common-beer-format.yeasts :as yeasts.format]
+ #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])))
+
+
+(deftest enrich-amount-is-weight-test
+ (testing "Ensure enricher doesn't alter the value of existing `:amount is weight` keys"
+ (is (nil? (:amount-is-weight yeasts.data/sample-yeast))
+ "yeasts.data/sample-yeast does not set `amount-is-weight`")
+ (is (false? (-> yeasts.data/sample-yeast
+ yeasts.enrich/enrich-amount-is-weight
+ :amount-is-weight))
+ "yeasts.data/sample-yeast does not set `amount-is-weight`, so the enricher sets the value to false")
+ (is (false? (-> yeasts.data/sample-yeast
+ (assoc :amount-is-weight false)
+ yeasts.enrich/enrich-amount-is-weight
+ :amount-is-weight))
+ "Explicitly setting `:amount-is-weight` to false causes the value to be retained")
+ (is (true? (-> yeasts.data/sample-yeast
+ (assoc :amount-is-weight true)
+ yeasts.enrich/enrich-amount-is-weight
+ :amount-is-weight))
+ "Explicitly setting `:amount-is-weight` to false causes the value to be retained"))
+ (testing "The two-arity version of `enrich-amount0is0-weight` has no behavioral differences"
+ (is (false? (-> yeasts.data/sample-yeast
+ (yeasts.enrich/enrich-amount-is-weight :some-value)
+ :amount-is-weight))
+ "yeasts.data/sample-yeast does not set `amount-is-weight`, so the enricher sets the value to false")
+ (is (false? (-> yeasts.data/sample-yeast
+ (assoc :amount-is-weight false)
+ (yeasts.enrich/enrich-amount-is-weight :some-value)
+ :amount-is-weight))
+ "Explicitly setting `:amount-is-weight` to false causes the value to be retained")
+ (is (true? (-> yeasts.data/sample-yeast
+ (assoc :amount-is-weight true)
+ (yeasts.enrich/enrich-amount-is-weight :some-value)
+ :amount-is-weight))
+ "Explicitly setting `:amount-is-weight` to false causes the value to be retained")))
+
+
+(deftest enrich-display-amount-test
+ (testing "Ensure enricher correctly defaults to setting display amount as a weight"
+ (let [weighted-yeast (assoc yeasts.data/sample-yeast :amount-is-weight true)]
+ (is (= "0.551 lb" (-> weighted-yeast
+ yeasts.enrich/enrich-display-amount
+ :display-amount))
+ "yeasts.data/sample-yeast sets the amount to 15.0, which is the default unit")
+ (is (= "34.293 lb" (-> weighted-yeast
+ (assoc :amount 15.555)
+ yeasts.enrich/enrich-display-amount
+ :display-amount))
+ "enrich-display-amount defaults precision to 3")
+ (is (= "34.29 lb" (-> weighted-yeast
+ (assoc :amount 15.555)
+ (yeasts.enrich/enrich-display-amount {:yeast-amount-precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision")
+ (is (= "15444.4 g" (-> weighted-yeast
+ (assoc :amount 15.4444)
+ (yeasts.enrich/enrich-display-amount {:yeast-amount-target-units :gram})
+ :display-amount))
+ "enrich-display-amount unites can be configured to use seconds")
+ (is (= "33.069 pound" (-> weighted-yeast
+ (assoc :amount 15.0)
+ (yeasts.enrich/enrich-display-amount {:yeast-amount-suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes")
+ (is (= "34.29 lb" (-> weighted-yeast
+ (assoc :amount 15.555)
+ (yeasts.enrich/enrich-display-amount {:precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision with default settings keys")
+ (is (= "15.4 kg" (-> weighted-yeast
+ (assoc :amount 15.4)
+ (yeasts.enrich/enrich-display-amount {:system-of-measure :metric})
+ :display-amount))
+ "enrich-display-amount unites can be configured with default settings keys")
+ (is (= "33.069 pound" (-> weighted-yeast
+ (assoc :amount 15.0)
+ (yeasts.enrich/enrich-display-amount {:suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes with default settings keys")))
+ (testing "Ensure enricher correctly defaults to setting display amount as a volume"
+ (let [volume-yeast (assoc yeasts.data/sample-yeast :amount-is-weight false)]
+ (is (= "0.066 gal" (-> volume-yeast
+ yeasts.enrich/enrich-display-amount
+ :display-amount))
+ "yeasts.data/sample-yeast sets the amount to 15.0, which is the default unit")
+ (is (= "4.109 gal" (-> volume-yeast
+ (assoc :amount 15.555)
+ yeasts.enrich/enrich-display-amount
+ :display-amount))
+ "enrich-display-amount defaults precision to 3")
+ (is (= "4.11 gal" (-> volume-yeast
+ (assoc :amount 15.555)
+ (yeasts.enrich/enrich-display-amount {:yeast-amount-precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision")
+ (is (= "3043.263 tsp" (-> volume-yeast
+ (assoc :amount 15.0)
+ (yeasts.enrich/enrich-display-amount {:yeast-amount-target-units :teaspoon})
+ :display-amount))
+ "enrich-display-amount unites can be configured to use seconds")
+ (is (= "3.963 US gallon" (-> volume-yeast
+ (assoc :amount 15.0)
+ (yeasts.enrich/enrich-display-amount {:yeast-amount-suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes")
+ (is (= "4.11 gal" (-> volume-yeast
+ (assoc :amount 15.555)
+ (yeasts.enrich/enrich-display-amount {:precision 2})
+ :display-amount))
+ "enrich-display-amount can be configured to use a different precision with default settings keys")
+ (is (= "15.1 l" (-> volume-yeast
+ (assoc :amount 15.1)
+ (yeasts.enrich/enrich-display-amount {:system-of-measure :metric})
+ :display-amount))
+ "enrich-display-amount unites can be configured with default settings keys")
+ (is (= "3.963 US gallon" (-> volume-yeast
+ (assoc :amount 15.0)
+ (yeasts.enrich/enrich-display-amount {:suffix :full})
+ :display-amount))
+ "enrich-display-amount can be configured to use full suffixes with default settings keys")))
+ (testing "Ensure resulting `yeast` still conforms to the spec"
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast (-> yeasts.data/sample-yeast
+ (assoc :amount-is-weight true)
+ yeasts.enrich/enrich-display-amount))
+ "yeasts.data/sample-yeast conforms to the spec if the amount is a weight")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast (-> yeasts.data/sample-yeast
+ (assoc :amount-is-weight false)
+ yeasts.enrich/enrich-display-amount))
+ "yeasts.data/sample-yeast conforms to the spec if the amount is a volume")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast (-> (yeasts.data/generate-yeast)
+ (assoc :amount-is-weight true)
+ yeasts.enrich/enrich-display-amount))
+ "yeasts.data/sample-yeast conforms to the spec if the amount is a weight")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast (-> (yeasts.data/generate-yeast)
+ (assoc :amount-is-weight false)
+ yeasts.enrich/enrich-display-amount))
+ "yeasts.data/sample-yeast conforms to the spec if the amount is a volume")))
+
+
+;;
+;; Whole object enrichment tests
+;;
+
+(deftest enrich-yeast-tests
+ (testing "Ensure enrichment pattern functions generate conforming data"
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast
+ (yeasts.enrich/enrich-yeast yeasts.data/sample-yeast))
+ "Enrichment pattern should produce a valid yeast object")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast-wrapper
+ (yeasts.enrich/enrich-yeast-wrapper yeasts.data/sample-yeast-wrapper))
+ "Enrichment pattern should produce a valid yeast object")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeasts
+ (yeasts.enrich/enrich-yeasts yeasts.data/sample-yeasts))
+ "Enrichment pattern should produce a valid yeast object")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeasts-wrapper
+ (yeasts.enrich/enrich-yeasts-wrapper yeasts.data/sample-yeasts-wrapper))
+ "Enrichment pattern should produce a valid yeast object")
+ (testing "Static data comparison for enrichment pattern functions"
+ (is (= {:amount 0.25
+ :amount-is-weight false
+ :attenuation 73.0
+ :best-for "Irish Dry Stouts"
+ :disp-max-temp "71.96 f"
+ :disp-min-temp "62.06 f"
+ :display-amount "0.066 gal"
+ :flocculation "Medium"
+ :form "Liquid"
+ :laboratory "Wyeast Labs"
+ :max-temperature 22.2
+ :min-temperature 16.7
+ :name "Irish Ale"
+ :notes "Dry, fruity flavor characteristic of stouts. Full bodied, dry, clean flavor."
+ :product-id "1084"
+ :type "Ale"
+ :version 1}
+ (yeasts.enrich/enrich-yeast yeasts.data/sample-yeast)))
+ (is (= {:amount 0.25
+ :amount-is-weight false
+ :attenuation 73.0
+ :best-for "Irish Dry Stouts"
+ :display-amount "0.066 gal"
+ :flocculation "Medium"
+ :form "Liquid"
+ :laboratory "Wyeast Labs"
+ :name "Irish Ale"
+ :notes "Dry, fruity flavor characteristic of stouts. Full bodied, dry, clean flavor."
+ :product-id "1084"
+ :type "Ale"
+ :version 1}
+ (yeasts.enrich/enrich-yeast (dissoc yeasts.data/sample-yeast :max-temperature :min-temperature)))))))
+
+
+(deftest generative-enrichment-tests
+ (testing "Ensure enrichment pattern works against arbitrary yeast"
+ (letfn [(gen-yeast [] (yeasts.data/generate-yeast))]
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast
+ (yeasts.enrich/enrich-amount-is-weight (gen-yeast)))
+ "enrich-amount-is-weight is a function to and from common-beer-format.yeast/yeast")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast
+ (yeasts.enrich/enrich-display-amount (gen-yeast)))
+ "enrich-display-amount is a function to and from common-beer-format.yeast/yeast")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast
+ (yeasts.enrich/enrich-yeast (gen-yeast)))
+ "enrich-yeast is a function to and from common-beer-format.yeast/yeast")))
+ (testing "Ensure enrichment pattern works against arbitrary yeast wrappers"
+ (is (spoon.spec/test-valid? ::yeasts.format/yeast-wrapper
+ (yeasts.enrich/enrich-yeast-wrapper (yeasts.data/generate-yeast-wrapper)))
+ "enrich-yeast-wrapper is a function to and from common-beer-format.yeast/yeast-wrapper")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeasts
+ (yeasts.enrich/enrich-yeasts (yeasts.data/generate-yeasts)))
+ "enrich-yeasts is a function to and from common-beer-format.yeast/yeasts")
+ (is (spoon.spec/test-valid? ::yeasts.format/yeasts-wrapper
+ (yeasts.enrich/enrich-yeasts-wrapper (yeasts.data/generate-yeasts-wrapper)))
+ "enrich-yeasts-wrapper is a function to and from common-beer-format.yeast/yeasts-wrapper")))
diff --git a/test/brewtility/precision_test.cljc b/test/brewtility/precision_test.cljc
index e0146b3..0f3d5fb 100644
--- a/test/brewtility/precision_test.cljc
+++ b/test/brewtility/precision_test.cljc
@@ -6,9 +6,22 @@
(deftest approximates?-test
(testing "Ensure approximation works as expected"
- (is (true? (sut/approximates? 100 100 0.00001)))
- (is (true? (sut/approximates? 100 90 0.1)))
- (is (false? (sut/approximates? 100 90 0.01)))))
+ (is (true? (sut/approximates? 100 100 0.00001))
+ "Equal numbers will always return true")
+ (is (let [r-int (rand-int 1000000)]
+ (true? (sut/approximates? r-int r-int 0.00001)))
+ "Equal integers will always return true")
+ (is (true? (sut/approximates? 100 90 0.1))
+ "90 is within 10% of 100")
+ (is (false? (sut/approximates? 100 90 0.01))
+ "90 is not within 1% of 100"))
+ (testing "Ensure that non-numeric values throw an exception"
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot approximate using non-numeric values" (sut/approximates? nil 100 0.00001))))
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot approximate using non-numeric values" (sut/approximates? 100 nil 0.00001))))
+ #?(:clj (is (thrown-with-msg? Exception #"Cannot approximate using non-numeric values" (sut/approximates? 100 100 nil))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot approximate using non-numeric values" (sut/approximates? nil 100 0.00001))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot approximate using non-numeric values" (sut/approximates? 100 nil 0.00001))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Cannot approximate using non-numeric values" (sut/approximates? 100 100 nil))))))
(deftest ->1dp-test
diff --git a/test/brewtility/predicates/equipment_test.cljc b/test/brewtility/predicates/equipment_test.cljc
index 9b4fdfd..e5bd147 100644
--- a/test/brewtility/predicates/equipment_test.cljc
+++ b/test/brewtility/predicates/equipment_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.equipment-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.equipment :as equipment]
[brewtility.predicates.equipment :as sut]
[common-beer-format.equipment :as cbf-equipment]))
diff --git a/test/brewtility/predicates/fermentables_test.cljc b/test/brewtility/predicates/fermentables_test.cljc
index d9bebbd..ebcbb39 100644
--- a/test/brewtility/predicates/fermentables_test.cljc
+++ b/test/brewtility/predicates/fermentables_test.cljc
@@ -1,8 +1,9 @@
(ns brewtility.predicates.fermentables-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.fermentables :as fermentables]
[brewtility.predicates.fermentables :as sut]
+ [brewtility.predicates.options :as options]
[common-beer-format.fermentables :as cbf-fermentables]))
@@ -20,7 +21,7 @@
(deftest grain?-test
(testing "A fermentable with a `:type` matching `\"grain\" returns true"
(is (true? (sut/grain? (assoc fermentables/sample-fermentable :type "Grain"))))
- (is (true? (sut/grain? (assoc fermentables/sample-fermentable :type cbf-fermentables/grain)))))
+ (is (true? (sut/grain? (assoc fermentables/sample-fermentable :type cbf-fermentables/grain) {options/uppercase? true}))))
(testing "A fermentable with a `:type` not matching `\"grain\" returns false"
(is (false? (sut/grain? (assoc fermentables/sample-fermentable :type "extract"))))
(is (false? (sut/grain? (assoc fermentables/sample-fermentable :type cbf-fermentables/extract))))
@@ -78,7 +79,7 @@
(is (false? (sut/extract? (assoc fermentables/sample-fermentable :type "Dry EXTract"))))
(is (false? (sut/extract? (assoc fermentables/sample-fermentable :type "adJunct"))))
(is (false? (sut/extract? (assoc fermentables/sample-fermentable :type cbf-fermentables/sugar))))
- (is (false? (sut/extract? (assoc fermentables/sample-fermentable :type cbf-fermentables/grain))))
+ (is (false? (sut/extract? (assoc fermentables/sample-fermentable :type cbf-fermentables/grain) {options/uppercase? true})))
(is (false? (sut/extract? (assoc fermentables/sample-fermentable :type cbf-fermentables/dry-extract))))
(is (false? (sut/extract? (assoc fermentables/sample-fermentable :type cbf-fermentables/adjunct)))))
(testing "This is a function from a fermentable to a boolean"
@@ -121,12 +122,13 @@
(deftest adjunct?-test
(testing "A fermentable with a `:type` matching `\"grain\" returns true"
(is (true? (sut/adjunct? (assoc fermentables/sample-fermentable :type "adJunct"))))
+ (is (true? (sut/adjunct? (assoc fermentables/sample-fermentable :type "adJunct") {options/uppercase? true})))
(is (true? (sut/adjunct? (assoc fermentables/sample-fermentable :type cbf-fermentables/adjunct)))))
(testing "A fermentable with a `:type` not matching `\"grain\" returns false"
(is (false? (sut/adjunct? (assoc fermentables/sample-fermentable :type "sugar"))))
(is (false? (sut/adjunct? (assoc fermentables/sample-fermentable :type "GRAIN"))))
(is (false? (sut/adjunct? (assoc fermentables/sample-fermentable :type "EXTract"))))
- (is (false? (sut/adjunct? (assoc fermentables/sample-fermentable :type "DRY EXTRact"))))
+ (is (false? (sut/adjunct? (assoc fermentables/sample-fermentable :type "DRY EXTRact") {options/uppercase? true})))
(is (false? (sut/adjunct? (assoc fermentables/sample-fermentable :type cbf-fermentables/sugar))))
(is (false? (sut/adjunct? (assoc fermentables/sample-fermentable :type cbf-fermentables/grain))))
(is (false? (sut/adjunct? (assoc fermentables/sample-fermentable :type cbf-fermentables/extract))))
@@ -141,3 +143,4 @@
#?(:cljs (is (thrown-with-msg? js/Error
#"Fermentable :type"
(sut/adjunct? (dissoc fermentables/sample-fermentable :type)))))))
+
diff --git a/test/brewtility/predicates/hops_test.cljc b/test/brewtility/predicates/hops_test.cljc
index 3f8b589..da2c727 100644
--- a/test/brewtility/predicates/hops_test.cljc
+++ b/test/brewtility/predicates/hops_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.hops-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.hops :as hops]
[brewtility.predicates.hops :as sut]
[common-beer-format.hops :as cbf-hops]))
diff --git a/test/brewtility/predicates/impl_test.cljc b/test/brewtility/predicates/impl_test.cljc
index f0564c8..0425b58 100644
--- a/test/brewtility/predicates/impl_test.cljc
+++ b/test/brewtility/predicates/impl_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.impl-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.predicates.impl :as sut]))
diff --git a/test/brewtility/predicates/mash_test.cljc b/test/brewtility/predicates/mash_test.cljc
index cbe16b3..7c98fe9 100644
--- a/test/brewtility/predicates/mash_test.cljc
+++ b/test/brewtility/predicates/mash_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.mash-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.mash :as mash]
[brewtility.predicates.mash :as sut]
[common-beer-format.mash :as cbf-mash]))
diff --git a/test/brewtility/predicates/miscs_test.cljc b/test/brewtility/predicates/miscs_test.cljc
index bb1bd63..6c52e8a 100644
--- a/test/brewtility/predicates/miscs_test.cljc
+++ b/test/brewtility/predicates/miscs_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.miscs-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.miscs :as miscs]
[brewtility.predicates.miscs :as sut]
[common-beer-format.miscs :as cbf-miscs]))
diff --git a/test/brewtility/predicates/options_test.cljc b/test/brewtility/predicates/options_test.cljc
new file mode 100644
index 0000000..07e0ea8
--- /dev/null
+++ b/test/brewtility/predicates/options_test.cljc
@@ -0,0 +1,9 @@
+(ns brewtility.predicates.options-test
+ (:require #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ [brewtility.predicates.options :as sut]))
+
+
+(deftest type-test
+ (testing "A sanity test for all option keywords"
+ (is (keyword? sut/uppercase?))))
diff --git a/test/brewtility/predicates/recipes_test.cljc b/test/brewtility/predicates/recipes_test.cljc
index 62edf9e..c101c70 100644
--- a/test/brewtility/predicates/recipes_test.cljc
+++ b/test/brewtility/predicates/recipes_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.recipes-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.recipes :as recipes]
[brewtility.predicates.recipes :as sut]
[common-beer-format.recipes :as cbf-recipes]))
diff --git a/test/brewtility/predicates/styles_test.cljc b/test/brewtility/predicates/styles_test.cljc
index 38baf37..3b69e68 100644
--- a/test/brewtility/predicates/styles_test.cljc
+++ b/test/brewtility/predicates/styles_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.styles-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.styles :as styles]
[brewtility.predicates.styles :as sut]
[common-beer-format.styles :as cbf-styles]))
diff --git a/test/brewtility/predicates/waters_test.cljc b/test/brewtility/predicates/waters_test.cljc
index 9913f5a..b736af5 100644
--- a/test/brewtility/predicates/waters_test.cljc
+++ b/test/brewtility/predicates/waters_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.waters-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.waters :as waters]
[brewtility.predicates.waters :as sut]
[common-beer-format.waters :as cbf-waters]))
diff --git a/test/brewtility/predicates/yeasts_test.cljc b/test/brewtility/predicates/yeasts_test.cljc
index c7b4a83..f1dc8ce 100644
--- a/test/brewtility/predicates/yeasts_test.cljc
+++ b/test/brewtility/predicates/yeasts_test.cljc
@@ -1,6 +1,6 @@
(ns brewtility.predicates.yeasts-test
(:require #? (:clj [clojure.test :refer [deftest is testing]])
- #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
[brewtility.data.yeasts :as yeasts]
[brewtility.predicates.yeasts :as sut]
[common-beer-format.yeasts :as cbf-yeasts]))
diff --git a/test/brewtility/runner.cljs b/test/brewtility/runner.cljs
index d4e6855..9752b63 100644
--- a/test/brewtility/runner.cljs
+++ b/test/brewtility/runner.cljs
@@ -1,6 +1,6 @@
(ns brewtility.runner
"The ClojureScript test runner for brewtility.
-
+
This namespace is responsible for running all of the ClojureScript tests.
To add new test namespaces, add them to the `:require` and `doo-tests` clauses below."
(:require [brewtility.calculations-test]
@@ -13,6 +13,13 @@
[brewtility.data.styles]
[brewtility.data.waters]
[brewtility.data.yeasts]
+ [brewtility.enrich.equipment-test]
+ [brewtility.enrich.fermentables-test]
+ [brewtility.enrich.hops-test]
+ [brewtility.enrich.mash-test]
+ [brewtility.enrich.miscs-test]
+ [brewtility.enrich.waters-test]
+ [brewtility.enrich.yeasts-test]
[brewtility.precision-test]
[brewtility.predicates.equipment-test]
[brewtility.predicates.fermentables-test]
@@ -20,11 +27,14 @@
[brewtility.predicates.impl-test]
[brewtility.predicates.mash-test]
[brewtility.predicates.miscs-test]
+ [brewtility.predicates.options-test]
[brewtility.predicates.recipes-test]
[brewtility.predicates.styles-test]
[brewtility.predicates.waters-test]
[brewtility.predicates.yeasts-test]
[brewtility.units-test]
+ [brewtility.units.bitterness-test]
+ [brewtility.units.carbonation-test]
[brewtility.units.color-test]
[brewtility.units.pressure-test]
[brewtility.units.specific-gravity-test]
@@ -36,6 +46,7 @@
[doo.runner :refer-macros [doo-tests]]))
+;; This should match the :require above (aside from doo itself)
(doo-tests 'brewtility.calculations-test
'brewtility.data.equipment
'brewtility.data.fermentables
@@ -46,6 +57,13 @@
'brewtility.data.styles
'brewtility.data.waters
'brewtility.data.yeasts
+ 'brewtility.enrich.equipment-test
+ 'brewtility.enrich.fermentables-test
+ 'brewtility.enrich.hops-test
+ 'brewtility.enrich.mash-test
+ 'brewtility.enrich.miscs-test
+ 'brewtility.enrich.waters-test
+ 'brewtility.enrich.yeasts-test
'brewtility.precision-test
'brewtility.predicates.equipment-test
'brewtility.predicates.fermentables-test
@@ -53,11 +71,14 @@
'brewtility.predicates.impl-test
'brewtility.predicates.mash-test
'brewtility.predicates.miscs-test
+ 'brewtility.predicates.options-test
'brewtility.predicates.recipes-test
'brewtility.predicates.styles-test
'brewtility.predicates.waters-test
'brewtility.predicates.yeasts-test
'brewtility.units-test
+ 'brewtility.units.bitterness-test
+ 'brewtility.units.carbonation-test
'brewtility.units.color-test
'brewtility.units.pressure-test
'brewtility.units.specific-gravity-test
diff --git a/test/brewtility/units/alcohol_content_test.cljc b/test/brewtility/units/alcohol_content_test.cljc
new file mode 100644
index 0000000..b2ce7ff
--- /dev/null
+++ b/test/brewtility/units/alcohol_content_test.cljc
@@ -0,0 +1,57 @@
+(ns brewtility.units.alcohol-content-test
+ (:require #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ [brewtility.precision :as precision]
+ [brewtility.units.alcohol-content :as sut]
+ [brewtility.units.options :as options]))
+
+
+(deftest conversion-test
+ (testing "Ensure various color unit conversions behave as expected"
+ (is (= 100.0
+ (precision/->2dp (sut/convert 100.0 options/abv options/abv))
+ (precision/->2dp (sut/convert 100.0 :abv :abv)))))
+ (testing "Invalid options throw an exception"
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/convert 10.0 :invalid :broken))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/convert 10.0 :invalid :broken))))))
+
+
+(deftest display-test
+ (testing "Ensure various color unit conversions behave as expected"
+ (is (= "15.3% abv"
+ (sut/display 0.153 :abv)
+ (sut/display 0.153 options/abv))))
+ (testing "Invalid options throw an exception"
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/display 10.0 :invalid))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/display 10.0 :invalid))))
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/display nil :abv))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/display nil :abv))))))
+
+
+(deftest code-type-tests
+ (testing "Ensure maps used for options are structurally correct"
+ (testing "Measurement types"
+ (is (set? sut/measurements))
+ (is (every? keyword? sut/measurements))
+ (is (not-empty sut/measurements)))
+ (testing "Measurement display names"
+ (is (map? sut/measurements->display-name))
+ (is (not-empty sut/measurements->display-name))
+ (is (every? keyword? (keys sut/measurements->display-name)))
+ (is (every? map? (vals sut/measurements->display-name)))
+ (is (every? #(contains? % options/full) (vals sut/measurements->display-name)))
+ (is (every? #(contains? % options/short) (vals sut/measurements->display-name))))
+ (testing "measurement->abv"
+ (is (map? sut/measurement->abv))
+ (is (not-empty sut/measurement->abv))
+ (is (every? keyword? (keys sut/measurement->abv)))
+ (is (every? ifn? (vals sut/measurement->abv))))
+ (testing "abv->measurement"
+ (is (map? sut/abv->measurement))
+ (is (not-empty sut/abv->measurement))
+ (is (every? keyword? (keys sut/abv->measurement)))
+ (is (= (set (keys sut/measurement->abv))
+ (set (keys sut/abv->measurement))
+ (set (keys sut/measurements->display-name))
+ sut/measurements))
+ (is (every? ifn? (vals sut/abv->measurement))))))
diff --git a/test/brewtility/units/bitterness_test.cljc b/test/brewtility/units/bitterness_test.cljc
new file mode 100644
index 0000000..37d1979
--- /dev/null
+++ b/test/brewtility/units/bitterness_test.cljc
@@ -0,0 +1,55 @@
+(ns brewtility.units.bitterness-test
+ (:require #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ [brewtility.precision :as precision]
+ [brewtility.units.bitterness :as sut]
+ [brewtility.units.options :as options]))
+
+
+(deftest conversion-test
+ (testing "Ensure various color unit conversions behave as expected"
+ (is (= 100.0
+ (precision/->2dp (sut/convert 100.0 options/ibu options/ibu))
+ (precision/->2dp (sut/convert 100.0 :ibu :ibu)))))
+ (testing "Invalid options throw an exception"
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/convert 10.0 :invalid :broken))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/convert 10.0 :invalid :broken))))))
+
+
+(deftest display-test
+ (testing "Ensure various color unit conversions behave as expected"
+ (is (= "1.5 ibu"
+ (sut/display 1.5 :ibu)
+ (sut/display 1.5 options/ibu))))
+ (testing "Invalid options throw an exception"
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/display 10.0 :invalid))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/display 10.0 :invalid))))))
+
+
+(deftest code-type-tests
+ (testing "Ensure maps used for options are structurally correct"
+ (testing "Measurement types"
+ (is (set? sut/measurements))
+ (is (every? keyword? sut/measurements))
+ (is (not-empty sut/measurements)))
+ (testing "Measurement display names"
+ (is (map? sut/measurements->display-name))
+ (is (not-empty sut/measurements->display-name))
+ (is (every? keyword? (keys sut/measurements->display-name)))
+ (is (every? map? (vals sut/measurements->display-name)))
+ (is (every? #(contains? % options/full) (vals sut/measurements->display-name)))
+ (is (every? #(contains? % options/short) (vals sut/measurements->display-name))))
+ (testing "measurement->ibu"
+ (is (map? sut/measurement->ibu))
+ (is (not-empty sut/measurement->ibu))
+ (is (every? keyword? (keys sut/measurement->ibu)))
+ (is (every? ifn? (vals sut/measurement->ibu))))
+ (testing "ibu->measurement"
+ (is (map? sut/ibu->measurement))
+ (is (not-empty sut/ibu->measurement))
+ (is (every? keyword? (keys sut/ibu->measurement)))
+ (is (= (set (keys sut/measurement->ibu))
+ (set (keys sut/ibu->measurement))
+ (set (keys sut/measurements->display-name))
+ sut/measurements))
+ (is (every? ifn? (vals sut/ibu->measurement))))))
diff --git a/test/brewtility/units/carbonation_test.cljc b/test/brewtility/units/carbonation_test.cljc
new file mode 100644
index 0000000..163956f
--- /dev/null
+++ b/test/brewtility/units/carbonation_test.cljc
@@ -0,0 +1,59 @@
+(ns brewtility.units.carbonation-test
+ (:require #? (:clj [clojure.test :refer [deftest is testing]])
+ #? (:cljs [cljs.test :refer-macros [deftest is testing]])
+ [brewtility.precision :as precision]
+ [brewtility.units.carbonation :as sut]
+ [brewtility.units.options :as options]))
+
+
+(deftest conversion-test
+ (testing "Ensure various color unit conversions behave as expected"
+ (is (= 100.0
+ (precision/->2dp (sut/convert 100.0 options/volumes-of-co2 options/volumes-of-co2))
+ (precision/->2dp (sut/convert 100.0 :volumes-of-co2 :volumes-of-co2))))
+ (is (= 51.02 (precision/->2dp (sut/convert 100.0 options/volumes-of-co2 options/grams-per-liter))))
+ (is (= 196.0 (precision/->2dp (sut/convert 100.0 options/grams-per-liter options/volumes-of-co2)))))
+ (testing "Invalid options throw an exception"
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/convert 10.0 :invalid :broken))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/convert 10.0 :invalid :broken))))))
+
+
+(deftest display-test
+ (testing "Ensure various color unit conversions behave as expected"
+ (is (= "1.5 vols"
+ (sut/display 1.5 :volumes-of-co2)
+ (sut/display 1.5 options/volumes-of-co2)))
+ (is (= "1.5 volumes of CO2"
+ (sut/display 1.5 :volumes-of-co2 {options/suffix options/full}))))
+ (testing "Invalid options throw an exception"
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/display 10.0 :invalid))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/display 10.0 :invalid))))))
+
+
+(deftest code-type-tests
+ (testing "Ensure maps used for options are structurally correct"
+ (testing "Measurement types"
+ (is (set? sut/measurements))
+ (is (every? keyword? sut/measurements))
+ (is (not-empty sut/measurements)))
+ (testing "Measurement display names"
+ (is (map? sut/measurements->display-name))
+ (is (not-empty sut/measurements->display-name))
+ (is (every? keyword? (keys sut/measurements->display-name)))
+ (is (every? map? (vals sut/measurements->display-name)))
+ (is (every? #(contains? % options/full) (vals sut/measurements->display-name)))
+ (is (every? #(contains? % options/short) (vals sut/measurements->display-name))))
+ (testing "measurement->volumes-of-co2"
+ (is (map? sut/measurement->volumes-of-co2))
+ (is (not-empty sut/measurement->volumes-of-co2))
+ (is (every? keyword? (keys sut/measurement->volumes-of-co2)))
+ (is (every? ifn? (vals sut/measurement->volumes-of-co2))))
+ (testing "volumes-of-co2->measurement"
+ (is (map? sut/volumes-of-co2->measurement))
+ (is (not-empty sut/volumes-of-co2->measurement))
+ (is (every? keyword? (keys sut/volumes-of-co2->measurement)))
+ (is (= (set (keys sut/measurement->volumes-of-co2))
+ (set (keys sut/volumes-of-co2->measurement))
+ (set (keys sut/measurements->display-name))
+ sut/measurements))
+ (is (every? ifn? (vals sut/volumes-of-co2->measurement))))))
diff --git a/test/brewtility/units/color_test.cljc b/test/brewtility/units/color_test.cljc
index de39d4e..e4f7be4 100644
--- a/test/brewtility/units/color_test.cljc
+++ b/test/brewtility/units/color_test.cljc
@@ -56,6 +56,53 @@
(is (= sut/srm-40 (sut/convert 41 options/srm options/rgba)))))
+(deftest rgba->srm-test
+ (testing "RGBA lookup behaves as expected"
+ (is (= 1 (sut/convert sut/srm-1 options/rgba options/srm)))
+ (is (= 2 (sut/convert sut/srm-2 options/rgba options/srm)))
+ (is (= 3 (sut/convert sut/srm-3 options/rgba options/srm)))
+ (is (= 4 (sut/convert sut/srm-4 options/rgba options/srm)))
+ (is (= 5 (sut/convert sut/srm-5 options/rgba options/srm)))
+ (is (= 6 (sut/convert sut/srm-6 options/rgba options/srm)))
+ (is (= 7 (sut/convert sut/srm-7 options/rgba options/srm)))
+ (is (= 8 (sut/convert sut/srm-8 options/rgba options/srm)))
+ (is (= 9 (sut/convert sut/srm-9 options/rgba options/srm)))
+ (is (= 10 (sut/convert sut/srm-10 options/rgba options/srm)))
+ (is (= 11 (sut/convert sut/srm-11 options/rgba options/srm)))
+ (is (= 12 (sut/convert sut/srm-12 options/rgba options/srm)))
+ (is (= 13 (sut/convert sut/srm-13 options/rgba options/srm)))
+ (is (= 14 (sut/convert sut/srm-14 options/rgba options/srm)))
+ (is (= 15 (sut/convert sut/srm-15 options/rgba options/srm)))
+ (is (= 16 (sut/convert sut/srm-16 options/rgba options/srm)))
+ (is (= 17 (sut/convert sut/srm-17 options/rgba options/srm)))
+ (is (= 18 (sut/convert sut/srm-18 options/rgba options/srm)))
+ (is (= 19 (sut/convert sut/srm-19 options/rgba options/srm)))
+ (is (= 20 (sut/convert sut/srm-20 options/rgba options/srm)))
+ (is (= 21 (sut/convert sut/srm-21 options/rgba options/srm)))
+ (is (= 22 (sut/convert sut/srm-22 options/rgba options/srm)))
+ (is (= 23 (sut/convert sut/srm-23 options/rgba options/srm)))
+ (is (= 24 (sut/convert sut/srm-24 options/rgba options/srm)))
+ (is (= 25 (sut/convert sut/srm-25 options/rgba options/srm)))
+ (is (= 26 (sut/convert sut/srm-26 options/rgba options/srm)))
+ (is (= 27 (sut/convert sut/srm-27 options/rgba options/srm)))
+ (is (= 28 (sut/convert sut/srm-28 options/rgba options/srm)))
+ (is (= 29 (sut/convert sut/srm-29 options/rgba options/srm)))
+ (is (= 30 (sut/convert sut/srm-30 options/rgba options/srm)))
+ (is (= 31 (sut/convert sut/srm-31 options/rgba options/srm)))
+ (is (= 32 (sut/convert sut/srm-32 options/rgba options/srm)))
+ (is (= 33 (sut/convert sut/srm-33 options/rgba options/srm)))
+ (is (= 34 (sut/convert sut/srm-34 options/rgba options/srm)))
+ (is (= 35 (sut/convert sut/srm-35 options/rgba options/srm)))
+ (is (= 36 (sut/convert sut/srm-36 options/rgba options/srm)))
+ (is (= 37 (sut/convert sut/srm-37 options/rgba options/srm)))
+ (is (= 38 (sut/convert sut/srm-38 options/rgba options/srm)))
+ (is (= 39 (sut/convert sut/srm-39 options/rgba options/srm)))
+ (is (= 40 (sut/convert sut/srm-40 options/rgba options/srm))))
+ (testing "Invalid RGBa strings throw an exception"
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported RGBa color value" (sut/convert "invalid" options/rgba options/srm))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported RGBa color value" (sut/convert "invalid" options/rgba options/srm))))))
+
+
(deftest lovibond->rgba-test
(testing "lovibond -> SRM -> rgba lookup behaves as expected"
(is (= sut/srm-13 (sut/convert 10.16 options/lovibond options/rgba)))
diff --git a/test/brewtility/units/specific_gravity_test.cljc b/test/brewtility/units/specific_gravity_test.cljc
index f386473..0e0da80 100644
--- a/test/brewtility/units/specific_gravity_test.cljc
+++ b/test/brewtility/units/specific_gravity_test.cljc
@@ -7,23 +7,43 @@
(deftest conversion-test
- (testing "Ensure various color unit conversions behave as expected"
+ (testing "Ensure various specific gravity unit conversions behave as expected"
(is (= 100.0
(precision/->2dp (sut/convert 100.0 options/specific-gravity options/specific-gravity))
- (precision/->2dp (sut/convert 100.0 :specific-gravity :specific-gravity)))))
+ (precision/->2dp (sut/convert 100.0 :specific-gravity :specific-gravity))))
+ (is (= 100.0
+ (precision/->2dp (sut/convert 100.0 options/plato options/plato))
+ (precision/->2dp (sut/convert 100.0 :plato :plato))))
+ (is (= 0.5 (precision/->1dp (sut/convert 1.002 options/specific-gravity options/plato))))
+ (is (= 3.1 (precision/->1dp (sut/convert 1.012 options/specific-gravity options/plato))))
+ (is (= 7.6 (precision/->1dp (sut/convert 1.03 options/specific-gravity options/plato))))
+ (is (= 19.6 (precision/->1dp (sut/convert 1.081 options/specific-gravity options/plato))))
+ (is (= 1.002 (precision/->3dp (sut/convert 0.5 options/plato options/specific-gravity))))
+ (is (= 1.012 (precision/->3dp (sut/convert 3.0 options/plato options/specific-gravity))))
+ (is (= 1.03 (precision/->3dp (sut/convert 7.5 options/plato options/specific-gravity))))
+ (is (= 1.081 (precision/->3dp (sut/convert 19.5 options/plato options/specific-gravity)))))
(testing "Invalid options throw an exception"
#?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/convert 10.0 :invalid :broken))))
- #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/convert 10.0 :invalid :broken))))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/convert 10.0 :invalid :broken))))
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/convert 10.0 :plato :broken))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/convert 10.0 :plato :broken))))
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/convert nil :plato :specific-gravity))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/convert nil :plato :specific-gravity))))))
(deftest display-test
- (testing "Ensure various color unit conversions behave as expected"
+ (testing "Ensure various specific gravity unit conversions behave as expected"
(is (= "1.5 sg"
(sut/display 1.5 :specific-gravity)
- (sut/display 1.5 options/specific-gravity))))
+ (sut/display 1.5 options/specific-gravity)))
+ (is (= "1.5 °P"
+ (sut/display 1.5 :plato)
+ (sut/display 1.5 options/plato))))
(testing "Invalid options throw an exception"
#?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/display 10.0 :invalid))))
- #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/display 10.0 :invalid))))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/display 10.0 :invalid))))
+ #?(:clj (is (thrown-with-msg? Exception #"Unsupported" (sut/display nil :plato))))
+ #?(:cljs (is (thrown-with-msg? js/Error #"Unsupported" (sut/display nil :plato))))))
(deftest code-type-tests
diff --git a/test/brewtility/units_test.cljc b/test/brewtility/units_test.cljc
index 991a91e..0b34d85 100644
--- a/test/brewtility/units_test.cljc
+++ b/test/brewtility/units_test.cljc
@@ -58,8 +58,7 @@
(precision/->2dp (sut/convert options/color 7.94 options/lovibond options/srm))
(precision/->2dp (sut/convert options/color 19.69 options/ebc options/srm))))
(is (= 10.0
- (precision/->2dp (sut/convert options/color 7.94 :lovibond :srm))
- (precision/->2dp (sut/convert options/color 19.69 :ebc :srm))))
+ (precision/->2dp (sut/convert options/color 7.94 :lovibond :srm))))
(is (= 23.2
(precision/->2dp (sut/convert options/color 30.66 options/srm options/lovibond))
(precision/->2dp (sut/convert options/color 60.38 options/ebc options/lovibond))))