Compare commits
	
		
			2 Commits
		
	
	
		
			7514e6bb22
			...
			b3be5fa90d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b3be5fa90d | |||
| fbd2222e1a | 
							
								
								
									
										153
									
								
								recipe.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								recipe.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,153 @@
 | 
				
			|||||||
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from anytree.importer import DictImporter
 | 
				
			||||||
 | 
					from sys import argv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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:
 | 
				
			||||||
 | 
					            html = f"<td rowspan='{self.rowspan}' colspan='{self.colspan}' title='{self.description}'>{self.name}</td>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Recipe:
 | 
				
			||||||
 | 
					    def __init__(self, json_filename: str):
 | 
				
			||||||
 | 
					        with open(json_filename, 'r') as f:
 | 
				
			||||||
 | 
					            recipe_dict = json.loads(f.read())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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"]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generate_ingredient_list(self):
 | 
				
			||||||
 | 
					        ingredients = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ingredients
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generate_task_list(self):
 | 
				
			||||||
 | 
					        tasks = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for sub_recipe in self.sub_recipes:
 | 
				
			||||||
 | 
					            tasks.extend(self.generate_steps_depth_first(sub_recipe, steps=[]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,125 +0,0 @@
 | 
				
			|||||||
import json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from anytree.importer import DictImporter
 | 
					 | 
				
			||||||
from sys import argv
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def build_table_depth_first(node, rows=None):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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>")
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            print(f"  <li>{ingredient.name}</li>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
print("</ul>")
 | 
					 | 
				
			||||||
print("</div>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
print("</ol>")
 | 
					 | 
				
			||||||
print("</div>")
 | 
					 | 
				
			||||||
print("</main>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
print("<summary>")
 | 
					 | 
				
			||||||
print("<h2>Tabular Layout</h2>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
for sub_recipe in sub_recipes:
 | 
					 | 
				
			||||||
    print("<p>")
 | 
					 | 
				
			||||||
    print("<table cellspacing='0' border=true>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    output_rows = build_table_depth_first(sub_recipe)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for row in output_rows:
 | 
					 | 
				
			||||||
        print("<tr>")
 | 
					 | 
				
			||||||
        for cell in row:
 | 
					 | 
				
			||||||
            print(f"  {cell}")
 | 
					 | 
				
			||||||
        print("</tr>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    print("</table>")
 | 
					 | 
				
			||||||
    print("</p>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
print("</summary>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
print("</body>")
 | 
					 | 
				
			||||||
print("</html>")
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user