Skip to content

Commit

Permalink
Add alcohol content measurements
Browse files Browse the repository at this point in the history
  • Loading branch information
nnichols committed Mar 11, 2024
1 parent 29b750b commit 6f05b56
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .sealog/changes/2-1-0.edn
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
:minor 1
:patch 0}
:version-type :semver3
:changes {:added ["`brewtility.units.bitterness` for rendering displayable IBU values."
: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."]
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## 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.
Expand Down
16 changes: 15 additions & 1 deletion src/brewtility/enrich/impl.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
: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]
Expand Down Expand Up @@ -59,6 +60,14 @@
: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
Expand Down Expand Up @@ -133,7 +142,8 @@

(def beer-xml-standard-units
"The standard units for each measurement type in BeerXML."
{options/bitterness options/ibu
{options/alcohol-content options/abv
options/bitterness options/ibu
options/carbonation options/volumes-of-co2
options/color options/srm
options/pressure options/kilopascal
Expand Down Expand Up @@ -165,6 +175,7 @@
"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
Expand Down Expand Up @@ -196,6 +207,7 @@
"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
Expand Down Expand Up @@ -273,6 +285,7 @@
: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)
Expand Down Expand Up @@ -322,6 +335,7 @@
"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)
Expand Down
9 changes: 7 additions & 2 deletions src/brewtility/units.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
{:added "1.0"
:changed "2.0"}
(: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]
Expand Down Expand Up @@ -49,7 +50,8 @@
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.bitterness/convert"
:see-also ["brewtility.units.alcohol-content/convert"
"brewtility.units.bitterness/convert"
"brewtility.units.carbonation/convert"
"brewtility.units.color/convert"
"brewtility.units.pressure/convert"
Expand All @@ -62,6 +64,7 @@
(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)
Expand Down Expand Up @@ -93,7 +96,8 @@
- `: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.bitterness/display"
:see-also ["brewtility.units.alcohol-content/display"
"brewtility.units.bitterness/display"
"brewtility.units.carbonation/display"
"brewtility.units.color/display"
"brewtility.units.pressure/display"
Expand All @@ -109,6 +113,7 @@
(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)
Expand Down
85 changes: 85 additions & 0 deletions src/brewtility/units/alcohol_content.cljc
Original file line number Diff line number Diff line change
@@ -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})))))
4 changes: 2 additions & 2 deletions src/brewtility/units/bitterness.cljc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(ns brewtility.units.bitterness
"A namespace for converting between different units of international bitterness units (IBU).
"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.
Expand All @@ -12,7 +12,7 @@


(def measurements
"The IBU systems available across brewtility."
"The bitterness measurement systems available across brewtility."
#{options/ibu})


Expand Down
43 changes: 31 additions & 12 deletions src/brewtility/units/options.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -116,27 +116,36 @@
#{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 or for a given unit.
"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:
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 or for a given unit.
"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:
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:
Expand All @@ -148,7 +157,7 @@


(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:
Expand All @@ -162,7 +171,7 @@


(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:
Expand All @@ -172,7 +181,7 @@


(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:
Expand All @@ -183,7 +192,7 @@


(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:
Expand All @@ -199,7 +208,7 @@


(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:
Expand All @@ -222,7 +231,7 @@


(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:
Expand All @@ -236,7 +245,8 @@

(def measurement-types
"The measurement types available across brewtility."
#{bitterness
#{alcohol-content
bitterness
carbonation
color
pressure
Expand All @@ -247,6 +257,14 @@
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.
Expand Down Expand Up @@ -299,6 +317,7 @@
Commonly used with `brewtility.units.color` and in argument/option maps."
:rgba)


;; Specific Gravity Units

(def plato
Expand Down
4 changes: 4 additions & 0 deletions src/brewtility/units/specific_gravity.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@

(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))
Expand Down
Loading

0 comments on commit 6f05b56

Please sign in to comment.