From 57b3a32f76c147cfb867443249036001f4cee997 Mon Sep 17 00:00:00 2001 From: Mike Shoup Date: Thu, 27 Dec 2018 16:04:04 -0700 Subject: [PATCH] Add hop table generation --- src/synthale/convert.py | 47 ++++++++++++++++++++++++++++++++++++++++- src/synthale/recipes.py | 38 ++++++++++++++++++++++++++++++++- tests/test_recipes.py | 22 +++++++++++++++++++ 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/synthale/convert.py b/src/synthale/convert.py index 0031cd6..2d468b0 100644 --- a/src/synthale/convert.py +++ b/src/synthale/convert.py @@ -1,4 +1,9 @@ -"""Contains functions used to convert units.""" +"""Contains functions used to convert units. + +Input units for volumes is liters. Input units for mass is kilograms. These +units are the defaults used in the BeerXML format, and as a result, in +`pybeerxml`. +""" def liters(liters, format_spec=''): @@ -19,3 +24,43 @@ def gallons(liters, format_spec=''): for how to write `format_spec`. """ return ('{:' + format_spec + '} gal').format(liters * 0.264178) + + +def kilograms(kilograms, format_spec=''): + """Return a string with the unit appended. + + See the `Format Specification Mini-Language + _` + for how to write `format_spec`. + """ + return ('{:' + format_spec + '} kg').format(kilograms) + + +def grams(kilograms, format_spec=''): + """Convert kilograms to grams and return a string with the unit appended. + + See the `Format Specification Mini-Language + _` + for how to write `format_spec`. + """ + return ('{:' + format_spec + '} g').format(kilograms * 1000.0) + + +def ounces(kilograms, format_spec=''): + """Convert kilograms to ounces and return a string with the unit appended. + + See the `Format Specification Mini-Language + _` + for how to write `format_spec`. + """ + return ('{:' + format_spec + '} oz').format(kilograms * 35.273962) + + +def pounds(kilograms, format_spec=''): + """Convert kilograms to pounds and return a string with the unit appended. + + See the `Format Specification Mini-Language + _` + for how to write `format_spec`. + """ + return ('{:' + format_spec + '} lb').format(kilograms * 2.204623) diff --git a/src/synthale/recipes.py b/src/synthale/recipes.py index 74312a7..b95604f 100644 --- a/src/synthale/recipes.py +++ b/src/synthale/recipes.py @@ -12,16 +12,21 @@ from synthale import markdown, convert class MarkdownRecipe: """A recipe in markdown form.""" - def __init__(self, recipe, vol_unit='gallons'): + def __init__(self, recipe, vol_unit='gallons', hop_unit='ounces'): """Create a MarkdownRecipe object. `recipe` is a recipe object from the pybeerxml package. `vol_unit` specifies the unit for boil size and batch size. Can be one of 'gallons', or 'liters'. + + `hop_unit` specifies the unit for hop amounts. Can be one of + 'ounces', 'pounds', 'grams', or 'kilograms'. If specified unit is not + matched, default is 'ounces'. """ self.recipe = recipe self.vol_unit = vol_unit + self.hop_unit = hop_unit @property def filename(self): @@ -49,6 +54,8 @@ class MarkdownRecipe: '', self.details, '', + self.hops, + '', )) @property @@ -101,6 +108,35 @@ class MarkdownRecipe: self.recipe.abv) )) + @property + def hops(self): + """Return markdown to represent the recipe's hops.""" + headers = ('Name', 'Origin', 'Alpha', 'Amount', 'Time', 'Use') + rows = [] + for hop in self.recipe.hops: + if self.hop_unit == 'pounds': + amt = convert.pounds(hop.amount, '.2f') + elif self.hop_unit == 'grams': + amt = convert.grams(hop.amount, '.1f') + elif self.hop_unit == 'kilograms': + amt = convert.kilograms(hop.amount, '.2f') + else: + amt = convert.ounces(hop.amount, '.1f') + rows.append(( + hop.name, + hop.origin, + '{:.1f} %'.format(hop.alpha), + amt, + '{}'.format(int(round(hop.time))), + hop.use, + )) + return ( + '{}\n{}'.format( + markdown.setext_heading('Hops', level=2), + markdown.table(headers, rows) + ) + ) + def load_file(path): """Parse BeerXML file located at `path`. diff --git a/tests/test_recipes.py b/tests/test_recipes.py index de3a0b6..3d0c62f 100644 --- a/tests/test_recipes.py +++ b/tests/test_recipes.py @@ -85,6 +85,28 @@ def test_recipe_details(md_weizen): assert '**Batch size**: 20.8 L' in md_weizen.details +def test_recipe_hops(md_weizen): + """Test valid hop table is generated.""" + md_weizen.hop_unit = 'ounces' + assert md_weizen.hops == ( + 'Hops\n' + '----\n' + '| Name | Origin | Alpha | Amount | Time | Use |\n' + '| -------------------- | ------- | ----- | ------ | ---- | ---- |\n' + '| Northern Brewer (DE) | Germany | 4.9 % | 1.0 oz | 60 | Boil |' + + ) + + md_weizen.hop_unit = 'pounds' + assert '| 0.06 lb |' in md_weizen.hops + + md_weizen.hop_unit = 'kilograms' + assert '| 0.03 kg |' in md_weizen.hops + + md_weizen.hop_unit = 'grams' + assert '| 28.3 g |' in md_weizen.hops + + def test_write_recipes(md_recipes, tmpdir): """Test write_recipes function.""" write_recipes(md_recipes, str(tmpdir))