Update recipe converter into an object.
This commit is contained in:
parent
fbd2222e1a
commit
b3be5fa90d
240
recipe.py
240
recipe.py
@ -4,122 +4,150 @@ from anytree.importer import DictImporter
|
||||
from sys import argv
|
||||
|
||||
|
||||
def build_table_depth_first(node, rows=None):
|
||||
class TableCell:
|
||||
def __init__(self, name, rowspan="", colspan="", description="", is_header=False):
|
||||
self.name = name
|
||||
self.rowspan = rowspan
|
||||
self.colspan = colspan
|
||||
self.description = description
|
||||
self.is_header = is_header
|
||||
|
||||
if rows is None:
|
||||
rows = []
|
||||
|
||||
for child in sorted(node.children, key=lambda x: x.height, reverse=True):
|
||||
rows = build_table_depth_first(child, rows)
|
||||
|
||||
colspan = 0
|
||||
if node.siblings:
|
||||
max_sibling_height = max([s.height for s in node.siblings])
|
||||
|
||||
if max_sibling_height > node.height:
|
||||
colspan = max_sibling_height - node.height + 1
|
||||
|
||||
if node.is_leaf:
|
||||
rows.append([f'<th>{node.name}</th>'])
|
||||
|
||||
if colspan > 1:
|
||||
rows[-1].append(f'<td colspan="{colspan-1}" class="filler"></td>')
|
||||
|
||||
else:
|
||||
child_leaves = len(node.leaves)
|
||||
cur_row = len(rows) - child_leaves
|
||||
rows[cur_row].append(f"<td rowspan='{child_leaves}' colspan='{colspan}' title='{node.description}'>{node.name}</td>")
|
||||
|
||||
return rows
|
||||
|
||||
|
||||
def generate_steps_depth_first(node, steps=[]):
|
||||
for child in sorted(node.children, key=lambda x: x.height, reverse=True):
|
||||
steps = generate_steps_depth_first(child, steps)
|
||||
|
||||
if not node.is_leaf:
|
||||
steps.append(node.description if node.description else node.name)
|
||||
|
||||
return steps
|
||||
|
||||
|
||||
if len(argv) < 2:
|
||||
print(f"usage: {argv[0]} <json file>")
|
||||
exit()
|
||||
|
||||
with open(argv[1], 'r') as f:
|
||||
recipe = json.loads(f.read())
|
||||
|
||||
recipe_name = recipe.get("name")
|
||||
recipe_desc = recipe.get("description")
|
||||
importer = DictImporter()
|
||||
sub_recipes = [importer.import_(data) for data in recipe["sub_recipes"]]
|
||||
|
||||
print("<!DOCTYPE html>")
|
||||
print("<html lang='en'>")
|
||||
print(f"<head><title>{recipe_name}</title>")
|
||||
print("<link rel='stylesheet' type='text/css' href='style.css'>")
|
||||
print("<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'>")
|
||||
print("</head>")
|
||||
print("<body>")
|
||||
|
||||
print("<header>")
|
||||
print("<div id='title'>")
|
||||
print(f"<h1>{recipe_name}</h1>")
|
||||
print("</div>")
|
||||
|
||||
print("<div id='description'>")
|
||||
print(f"<p>{recipe_desc}</p>")
|
||||
print("</div>")
|
||||
print("</header>")
|
||||
|
||||
print("<main>")
|
||||
print("<div id='needs'>")
|
||||
print("<h2>Needs</h2>")
|
||||
print("<ul>")
|
||||
|
||||
for sub_recipe in sub_recipes:
|
||||
for ingredient in sub_recipe.leaves:
|
||||
if ingredient.description:
|
||||
print(f" <li>{ingredient.name} -- {ingredient.description}</li>")
|
||||
def to_html(self):
|
||||
if self.is_header:
|
||||
html = f"<th title={self.description}>{self.name}</th>"
|
||||
elif not self.name:
|
||||
html = f'<td colspan="{self.colspan}" class="filler"></td>'
|
||||
else:
|
||||
print(f" <li>{ingredient.name}</li>")
|
||||
html = f"<td rowspan='{self.rowspan}' colspan='{self.colspan}' title='{self.description}'>{self.name}</td>"
|
||||
|
||||
print("</ul>")
|
||||
print("</div>")
|
||||
return html
|
||||
|
||||
print("<div id='preparation'>")
|
||||
print("<h2>Preparation</h2>")
|
||||
print("<ol>")
|
||||
|
||||
for sub_recipe in sub_recipes:
|
||||
tasks = generate_steps_depth_first(sub_recipe, steps=[])
|
||||
for task in tasks:
|
||||
print(f" <li>{task}</li>")
|
||||
class Recipe:
|
||||
def __init__(self, json_filename: str):
|
||||
with open(json_filename, 'r') as f:
|
||||
recipe_dict = json.loads(f.read())
|
||||
|
||||
print("</ol>")
|
||||
print("</div>")
|
||||
print("</main>")
|
||||
self.name = recipe_dict.get("name")
|
||||
self.desc = recipe_dict.get("description")
|
||||
importer = DictImporter()
|
||||
self.sub_recipes = [importer.import_(data) for data in recipe_dict["sub_recipes"]]
|
||||
|
||||
print("<summary>")
|
||||
print("<h2>Tabular Layout</h2>")
|
||||
def generate_ingredient_list(self):
|
||||
ingredients = []
|
||||
|
||||
for sub_recipe in sub_recipes:
|
||||
print("<p>")
|
||||
print("<table cellspacing='0' border=true>")
|
||||
for sub_recipe in self.sub_recipes:
|
||||
for ingredient in sub_recipe.leaves:
|
||||
if ingredient.description:
|
||||
ingredients.append(f"{ingredient.name} -- {ingredient.description}")
|
||||
else:
|
||||
ingredients.append(ingredient.name)
|
||||
|
||||
output_rows = build_table_depth_first(sub_recipe)
|
||||
return ingredients
|
||||
|
||||
for row in output_rows:
|
||||
print("<tr>")
|
||||
for cell in row:
|
||||
print(f" {cell}")
|
||||
print("</tr>")
|
||||
def generate_task_list(self):
|
||||
tasks = []
|
||||
|
||||
print("</table>")
|
||||
print("</p>")
|
||||
for sub_recipe in self.sub_recipes:
|
||||
tasks.extend(self.generate_steps_depth_first(sub_recipe, steps=[]))
|
||||
|
||||
print("</summary>")
|
||||
return tasks
|
||||
|
||||
def generate_steps_depth_first(self, node, steps=[]):
|
||||
for child in sorted(node.children, key=lambda x: x.height, reverse=True):
|
||||
steps = self.generate_steps_depth_first(child, steps)
|
||||
|
||||
if not node.is_leaf:
|
||||
steps.append(node.description if node.description else node.name)
|
||||
|
||||
return steps
|
||||
|
||||
def generate_tables(self):
|
||||
tables = []
|
||||
|
||||
for sub_recipe in self.sub_recipes:
|
||||
tables.append(self.build_table_rows_depth_first(sub_recipe))
|
||||
|
||||
return tables
|
||||
|
||||
def build_table_rows_depth_first(self, node, rows=None):
|
||||
if rows is None:
|
||||
rows = []
|
||||
|
||||
for child in sorted(node.children, key=lambda x: x.height, reverse=True):
|
||||
rows = self.build_table_rows_depth_first(child, rows)
|
||||
|
||||
colspan = 0
|
||||
if node.siblings:
|
||||
max_sibling_height = max([s.height for s in node.siblings])
|
||||
|
||||
if max_sibling_height > node.height:
|
||||
colspan = max_sibling_height - node.height + 1
|
||||
|
||||
if node.is_leaf:
|
||||
rows.append([TableCell(node.name, description=node.description, is_header=True)])
|
||||
|
||||
if colspan > 1:
|
||||
rows[-1].append(TableCell("", colspan=colspan-1))
|
||||
|
||||
else:
|
||||
child_leaves = len(node.leaves)
|
||||
cur_row = len(rows) - child_leaves
|
||||
rows[cur_row].append(TableCell(node.name, rowspan=child_leaves, colspan=colspan, description=node.description))
|
||||
|
||||
return rows
|
||||
|
||||
def to_html(self):
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
<head><title>{self.name}</title>
|
||||
<link rel='stylesheet' type='text/css' href='style.css'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<nav><a href='./'>Recipe Index</a></nav>
|
||||
<h1>{self.name}</h1>
|
||||
<p>{self.desc}</p>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div id='needs'>
|
||||
<h2>Needs</h2>
|
||||
<ul>
|
||||
{"\n".join([f" <li>{ingredient}</li>" for ingredient in self.generate_ingredient_list()])}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id='preparation'>
|
||||
<h2>Preparation</h2>
|
||||
<ol>
|
||||
{"\n".join([f" <li>{task}</li>" for task in self.generate_task_list()])}
|
||||
</ol>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<summary>
|
||||
<h2>Tabular Layout</h2>
|
||||
{"\n".join(
|
||||
[f"<table cellspacing=0 border=true>\n{"".join(
|
||||
[f"<tr>\n{"".join(
|
||||
[f" {cell.to_html()}\n" for cell in row]
|
||||
)}</tr>\n" for row in table]
|
||||
)}</table>" for table in self.generate_tables()]
|
||||
)}
|
||||
</summary>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(argv) < 2:
|
||||
print(f"usage: {argv[0]} <json file>")
|
||||
exit(1)
|
||||
|
||||
print(Recipe(argv[1]).to_html())
|
||||
|
||||
print("</body>")
|
||||
print("</html>")
|
||||
|
Loading…
x
Reference in New Issue
Block a user