From 2c50a4b513e689134eceba0acf9477bef212424b Mon Sep 17 00:00:00 2001 From: Mike Shoup Date: Sun, 23 Dec 2018 19:54:34 -0700 Subject: [PATCH] Add generation of details --- src/synthale/convert.py | 21 +++++++++++++++++++++ src/synthale/recipes.py | 41 +++++++++++++++++++++++++++++++++++++++-- tests/conftest.py | 8 ++++++++ tests/test_convert.py | 13 +++++++++++++ tests/test_recipes.py | 23 +++++++++++++++++++++++ 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 src/synthale/convert.py create mode 100644 tests/test_convert.py diff --git a/src/synthale/convert.py b/src/synthale/convert.py new file mode 100644 index 0000000..0031cd6 --- /dev/null +++ b/src/synthale/convert.py @@ -0,0 +1,21 @@ +"""Contains functions used to convert units.""" + + +def liters(liters, format_spec=''): + """Return a string with the unit appended. + + See the `Format Specification Mini-Language + _` + for how to write `format_spec`. + """ + return ('{:' + format_spec + '} L').format(liters) + + +def gallons(liters, format_spec=''): + """Convert liters to gallons and return a string with the unit appended. + + See the `Format Specification Mini-Language + _` + for how to write `format_spec`. + """ + return ('{:' + format_spec + '} gal').format(liters * 0.264178) diff --git a/src/synthale/recipes.py b/src/synthale/recipes.py index 2c89a96..de913a8 100644 --- a/src/synthale/recipes.py +++ b/src/synthale/recipes.py @@ -6,18 +6,22 @@ import sys import pybeerxml -from synthale import markdown +from synthale import markdown, convert class MarkdownRecipe: """A recipe in markdown form.""" - def __init__(self, recipe): + def __init__(self, recipe, vol_unit='gallons'): """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'. """ self.recipe = recipe + self.vol_unit = vol_unit @property def filename(self): @@ -43,6 +47,8 @@ class MarkdownRecipe: '', self.style, '', + self.details, + '', )) @property @@ -64,6 +70,37 @@ class MarkdownRecipe: self.recipe.style.name) )) + @property + def details(self): + """Return markdown for the recipe's details.""" + if self.vol_unit == 'gallons': + boil_size = convert.gallons(self.recipe.boil_size, '.1f') + batch_size = convert.gallons(self.recipe.batch_size, '.1f') + else: + boil_size = convert.liters(self.recipe.boil_size, '.1f') + batch_size = convert.liters(self.recipe.batch_size, '.1f') + + return '\n'.join(( + markdown.setext_heading('Details', 2), + '{}: {}'.format(markdown.strong('Type'), self.recipe.type), + '{}: {:.1f} %'.format(markdown.strong('Batch efficiency'), + self.recipe.efficiency), + '{}: {}'.format(markdown.strong('Boil size'), boil_size), + '{}: {} min'.format(markdown.strong('Boil length'), + int(self.recipe.boil_time)), + '{}: {}'.format(markdown.strong('Batch size'), batch_size), + '{}: {:.3f}'.format(markdown.strong('Estimated OG'), + self.recipe.og), + '{}: {:.3f}'.format(markdown.strong('Estimated FG'), + self.recipe.fg), + '{}: {}'.format(markdown.strong('Estimated IBU'), + int(self.recipe.ibu)), + '{}: {}'.format(markdown.strong('Estimated SRM'), + 'not implemented'), + '{}: {:.1f}'.format(markdown.strong('Estimated ABV'), + self.recipe.abv) + )) + def load_file(path): """Parse BeerXML file located at `path`. diff --git a/tests/conftest.py b/tests/conftest.py index 41d96d7..dd41e29 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,3 +20,11 @@ def md_recipes(): coffeestout = pybeerxml.Parser().parse('tests/recipes/coffee-stout.xml')[0] weizen = pybeerxml.Parser().parse('tests/recipes/weizen.xml')[0] return [MarkdownRecipe(coffeestout), MarkdownRecipe(weizen)] + + +@pytest.fixture +def md_weizen(): + """Return the sample weizen recipe as a MarkdownRecipe object.""" + return MarkdownRecipe( + pybeerxml.Parser().parse('tests/recipes/weizen.xml')[0] + ) diff --git a/tests/test_convert.py b/tests/test_convert.py new file mode 100644 index 0000000..f9f64ce --- /dev/null +++ b/tests/test_convert.py @@ -0,0 +1,13 @@ +"""Contains tests for the synthale.convert module.""" + +from synthale.convert import liters, gallons + + +def test_liters(): + """Test liters function.""" + assert liters(1, '.1f') == '1.0 L' + + +def test_gallons(): + """Test gallons function.""" + assert gallons(1, '.1f') == '0.3 gal' diff --git a/tests/test_recipes.py b/tests/test_recipes.py index 7ba6fb6..be5e9ea 100644 --- a/tests/test_recipes.py +++ b/tests/test_recipes.py @@ -62,6 +62,29 @@ def test_markdown_recipe_style(): ) +def test_recipe_details(md_weizen): + """Test valid details are generated.""" + md_weizen.vol_unit = 'gallons' + assert md_weizen.details == ( + 'Details\n' + '-------\n' + '**Type**: All Grain\n' + '**Batch efficiency**: 72.0 %\n' + '**Boil size**: 6.3 gal\n' + '**Boil length**: 60 min\n' + '**Batch size**: 5.5 gal\n' + '**Estimated OG**: 1.051\n' + '**Estimated FG**: 1.015\n' + '**Estimated IBU**: 15\n' + '**Estimated SRM**: not implemented\n' + '**Estimated ABV**: 4.7' + ) + + md_weizen.vol_unit = 'liters' + assert '**Boil size**: 23.7 L' in md_weizen.details + assert '**Batch size**: 20.8 L' in md_weizen.details + + def test_write_recipes(md_recipes, tmpdir): """Test write_recipes function.""" write_recipes(md_recipes, str(tmpdir))