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 + +The GitHub profile pictures of all current contributors. Clicking this image will lead you to the GitHub contribution graph. + ## 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))))