コード例 #1
0
    def test_recipes_split_across_blocks(self) -> None:
        compiled = compile_markdown(
            dedent("""
                A recipe in two parts. Part one:

                    sauce = boil down(tomatoes, water)

                Part two:

                    pour over(pasta, sauce)
                """).strip())

        sr = SubRecipe(
            Step(
                SVS("boil down"),
                (
                    Ingredient(SVS("tomatoes")),
                    Ingredient(SVS("water")),
                ),
            ),
            (SVS("sauce"), ),
        )
        r1 = Recipe((sr, ))
        r2 = Recipe(
            (Step(
                SVS("pour over"),
                (
                    Ingredient(SVS("pasta")),
                    Reference(sr),
                ),
            ), ),
            follows=r1,
        )

        assert compiled.recipes == [[r1, r2]]
コード例 #2
0
ファイル: test_recipe.py プロジェクト: mossblaser/recipe_grid
    def test_scale(self) -> None:
        step = Step(SVS(["fry in ", 4, " blocks"]),
                    (Ingredient(SVS("spam"), Quantity(2)), ))

        assert step.scale(3) == Step(
            SVS(["fry in ", 12, " blocks"]),
            (Ingredient(SVS("spam"), Quantity(6)), ),
        )
コード例 #3
0
 def test_compilation_of_steps(self) -> None:
     assert compile(["fry(slice(spam), eggs)"]) == [
         Recipe((Step(
             SVS("fry"),
             (
                 Step(SVS("slice"), (Ingredient(SVS("spam")), )),
                 Ingredient(SVS("eggs")),
             ),
         ), )),
     ]
コード例 #4
0
 def test_inlining_single_references_name_explicitly_required(self) -> None:
     assert compile(["meat := spam, sliced\nfry(meat, eggs)"]) == [
         Recipe((Step(
             SVS("fry"),
             (
                 SubRecipe(
                     Step(SVS("sliced"), (Ingredient(SVS("spam")), )),
                     (SVS("meat"), ),
                 ),
                 Ingredient(SVS("eggs")),
             ),
         ), ))
     ]
コード例 #5
0
 def test_inlining_single_references(self, quantity_spec: str) -> None:
     assert compile(
         [f"meat = 10g spam, sliced\nfry({quantity_spec} meat, eggs)"]) == [
             Recipe((Step(
                 SVS("fry"),
                 (
                     Step(
                         SVS("sliced"),
                         (Ingredient(SVS("spam"), Quantity(10, "g")), ),
                     ),
                     Ingredient(SVS("eggs")),
                 ),
             ), ))
         ]
コード例 #6
0
    def test_separate_recipes(self) -> None:
        compiled = compile_markdown(
            dedent("""
                Fried egg:

                ```recipe
                1 egg
                ```

                ```recipe
                fry(egg)
                ```

                Boiled egg:

                ```new-recipe
                2 egg
                ```

                ```recipe
                boil(egg)
                ```
                """).strip())

        e1 = SubRecipe(
            Ingredient(SVS("egg"), Quantity(1)),
            (SVS("egg"), ),
            show_output_names=False,
        )
        r1 = Recipe((e1, ))
        r2 = Recipe((Step(SVS("fry"), (Reference(e1), )), ), follows=r1)

        e2 = SubRecipe(
            Ingredient(SVS("egg"), Quantity(2)),
            (SVS("egg"), ),
            show_output_names=False,
        )
        r3 = Recipe((e2, ))
        r4 = Recipe((Step(SVS("boil"), (Reference(e2), )), ), follows=r3)

        assert compiled.recipes == [[r1, r2], [r3, r4]]

        # Check anchor IDs are unique too
        html = compiled.render()
        assert 'id="recipe-egg"' in html
        assert 'href="#recipe-egg"' in html
        assert 'id="recipe2-egg"' in html
        assert 'href="#recipe2-egg"' in html
コード例 #7
0
 def test_reference_compilation(self) -> None:
     sub_recipe = SubRecipe(
         Step(SVS("open"), (Ingredient(SVS("spam")), )),
         (SVS("spam"), SVS("tin")),
         True,
     )
     assert compile([
         "spam, tin = open(spam)\nspam\n1/3*spam\n25% of the spam\nleft over spam\n2 'tin'\n50g spam"  # noqa: E501
     ]) == [
         Recipe((
             sub_recipe,
             # spam
             Reference(sub_recipe, 0, Proportion(1.0)),
             # 1/3*spam
             Reference(sub_recipe, 0,
                       Proportion(Fraction(1, 3), preposition="*")),
             # 25% of the spam
             Reference(
                 sub_recipe,
                 0,
                 Proportion(0.25, percentage=True, preposition="% of the"),
             ),
             # remaining
             Reference(sub_recipe, 0,
                       Proportion(None, remainder_wording="left over")),
             # 2 tin
             Reference(sub_recipe, 1, Quantity(2.0)),
             # 50g spam
             Reference(sub_recipe, 0, Quantity(50.0, "g")),
         )),
     ]
コード例 #8
0
ファイル: test_recipe.py プロジェクト: mossblaser/recipe_grid
    def test_nested_reference_to_sub_recipe_not_in_recipe(self) -> None:
        external_sr = SubRecipe(Ingredient(SVS("eggs")), (SVS("foo"), ))
        ref = Reference(external_sr)
        step = Step(SVS("bar"), (ref, ))

        with pytest.raises(ReferenceToInvalidSubRecipeError):
            Recipe((step, ))
コード例 #9
0
ファイル: test_recipe.py プロジェクト: mossblaser/recipe_grid
    def test_reference_to_nested_sub_recipe(self) -> None:
        nested_sr = SubRecipe(Ingredient(SVS("eggs")), (SVS("foo"), ))
        step = Step(SVS("scramble"), (nested_sr, ))

        ref = Reference(nested_sr)

        with pytest.raises(ReferenceToInvalidSubRecipeError):
            Recipe((step, ref))
コード例 #10
0
 def test_inlines_within_inlines(self) -> None:
     recipe = Recipe((Step(
         SVS("boil"),
         (
             SubRecipe(
                 Step(
                     SVS("fry"),
                     (Ingredient(SVS("spam"), Quantity(100, "g")), ),
                 ),
                 (SVS("fried spam"), ),
             ),
             Ingredient(SVS("water")),
         ),
     ), ))
     assert compile([
         "100g spam\nfried spam := fry(spam)\nboil(fried spam, water)"
     ]) == [recipe]
コード例 #11
0
 def test_processed_ingredient_with_implied_output_name(
         self, syntax: str) -> None:
     assert compile([syntax]) == [
         Recipe((SubRecipe(
             Step(SVS("fry"), (Ingredient(SVS("spam")), )),
             (SVS("spam"), ),
             False,
         ), )),
     ]
コード例 #12
0
def test_step() -> None:
    input_0 = Ingredient(SVS("input 0"))
    input_1 = Ingredient(SVS("input 1"))

    input_2_ingredient = Ingredient(SVS("input 2"))
    input_2 = Step(SVS("chopped"), (input_2_ingredient, ))
    step = Step(SVS("combine"), (input_0, input_1, input_2))

    assert recipe_tree_to_table(step) == set_border_around_table(
        Table.from_dict(
            cast(
                Mapping[Tuple[int, int], Cell[RecipeTreeNode]],
                {
                    (0, 0): Cell(input_0, columns=2),
                    (1, 0): Cell(input_1, columns=2),
                    (2, 0): Cell(input_2_ingredient),
                    (2, 1): Cell(input_2),
                    (0, 2): Cell(step, rows=3),
                },
            )),
        BorderType.sub_recipe,
    )
コード例 #13
0
def test_single_output_sub_recipe_hidden() -> None:
    ingredient = Ingredient(SVS("spam"))
    step = Step(SVS("fry"), (ingredient, ))
    sub_recipe = SubRecipe(step, (SVS("out"), ), show_output_names=False)

    assert recipe_tree_to_table(sub_recipe) == set_border_around_table(
        Table.from_dict(
            cast(
                Mapping[Tuple[int, int], Cell[RecipeTreeNode]],
                {
                    (0, 0): Cell(ingredient),
                    (0, 1): Cell(step)
                },
            )),
        BorderType.sub_recipe,
    )
コード例 #14
0
ファイル: test_recipe.py プロジェクト: mossblaser/recipe_grid
    def test_substitute(self) -> None:
        a = Ingredient(SVS("a"))
        b = Ingredient(SVS("b"))
        c = Ingredient(SVS("c"))
        d = Ingredient(SVS("d"))

        orig = Step(SVS("stir"), (a, b))

        assert orig.substitute(a, c) == Step(SVS("stir"), (c, b))
        assert orig.substitute(orig, c) == c
        assert orig.substitute(d, c) == orig
コード例 #15
0
 def test_dont_inline_partial_uses_of_a_subrecipe(self) -> None:
     sub_recipe = SubRecipe(
         Ingredient(SVS("spam"), Quantity(100, "g")),
         (SVS("spam"), ),
         False,
     )
     assert compile(["100g spam\nfry(50g spam, eggs)"]) == [
         Recipe((
             sub_recipe,
             Step(
                 SVS("fry"),
                 (
                     Reference(sub_recipe, 0, Quantity(50, "g")),
                     Ingredient(SVS("eggs")),
                 ),
             ),
         ))
     ]
コード例 #16
0
 def test_dont_inline_multi_output_subrecipes(self) -> None:
     sub_recipe = SubRecipe(
         Ingredient(SVS("spam")),
         (SVS("meat"), SVS("tin")),
         True,
     )
     assert compile(["meat, tin = spam\nfry(meat, eggs)"]) == [
         Recipe((
             sub_recipe,
             Step(
                 SVS("fry"),
                 (
                     Reference(sub_recipe, 0),
                     Ingredient(SVS("eggs")),
                 ),
             ),
         ))
     ]
コード例 #17
0
 def test_inlining_within_a_block(self) -> None:
     recipe0 = Recipe((SubRecipe(Ingredient(SVS("egg")), (SVS("egg"), ),
                                 show_output_names=False), ))
     recipe1 = Recipe(
         (Step(SVS("fry"),
               (Ingredient(SVS("spam"), Quantity(50, "g")), )), ),
         follows=recipe0,
     )
     recipe2 = Recipe(
         (SubRecipe(Ingredient(SVS("potato")), (SVS("potato"), ),
                    show_output_names=False), ),
         follows=recipe1,
     )
     assert compile(["egg", "50g spam\nfry(spam)", "potato"]) == [
         recipe0,
         recipe1,
         recipe2,
     ]
コード例 #18
0
 def test_dont_inline_definitions_from_earlier_blocks(self) -> None:
     sub_recipe = SubRecipe(
         Ingredient(SVS("spam"), Quantity(100, "g")),
         (SVS("spam"), ),
         False,
     )
     recipe0 = Recipe((sub_recipe, ))
     recipe1 = Recipe(
         (Step(
             SVS("fry"),
             (
                 Reference(sub_recipe, 0, Quantity(50, "g")),
                 Ingredient(SVS("eggs")),
             ),
         ), ),
         follows=recipe0,
     )
     assert compile(["100g spam",
                     "fry(50g spam, eggs)"]) == [recipe0, recipe1]
コード例 #19
0
ファイル: test_html.py プロジェクト: mossblaser/recipe_grid
def test_render_table(id: Optional[str], exp_attrs: str) -> None:
    assert render_table(
        Table.from_dict({
            (0, 0):
            Cell(Ingredient(SVS("spam"))),
            (1, 0):
            Cell(Ingredient(SVS("eggs"))),
            (0, 1):
            Cell(
                Step(SVS("fry"),
                     (Ingredient(SVS("spam")), Ingredient(SVS("eggs")))),
                rows=2,
            ),
        }),
        id=id,
    ) == (f'<table class="rg-table"{exp_attrs}>\n'
          "  <tr>\n"
          '    <td class="rg-ingredient">spam</td>\n'
          '    <td class="rg-step" rowspan="2">fry</td>\n'
          "  </tr>\n"
          '  <tr><td class="rg-ingredient">eggs</td></tr>\n'
          "</table>")
コード例 #20
0
def test_multiple_output_sub_recipe() -> None:
    ingredient_0 = Ingredient(SVS("spam"))
    ingredient_1 = Ingredient(SVS("eggs"))
    ingredient_2 = Ingredient(SVS("more spam"))
    step = Step(SVS("fry"), (ingredient_0, ingredient_1, ingredient_2))
    sub_recipe = SubRecipe(step, (SVS("output 0"), SVS("output 1")))

    assert recipe_tree_to_table(sub_recipe) == combine_tables(
        cast(
            List[Table[RecipeTreeNode]],
            [
                set_border_around_table(
                    Table.from_dict(
                        cast(
                            Mapping[Tuple[int, int], Cell[RecipeTreeNode]],
                            {
                                (0, 0): Cell(ingredient_0),
                                (1, 0): Cell(ingredient_1),
                                (2, 0): Cell(ingredient_2),
                                (0, 1): Cell(step, rows=3),
                            },
                        )),
                    BorderType.sub_recipe,
                ),
                Table.from_dict({
                    (0, 0):
                    Cell(
                        sub_recipe,
                        rows=3,
                        border_top=BorderType.none,
                        border_right=BorderType.none,
                        border_bottom=BorderType.none,
                    )
                }),
            ],
        ),
        axis=1,
    )
コード例 #21
0
    def test_recipe_code_blocks_and_scaled_rendering(self,
                                                     source: str) -> None:
        compiled = compile_markdown(dedent(source).strip())
        assert compiled.title == "A recipe"
        assert compiled.servings == 2
        assert compiled.recipes == [[
            Recipe((Step(
                SVS("fry"),
                (
                    Ingredient(SVS("spam"), Quantity(100, "g")),
                    Ingredient(SVS("eggs"), Quantity(2)),
                ),
            ), )),
        ]]
        assert (compiled.render(2) == dedent("""
                <header><h1 class="rg-title-scalable">A recipe <span class="rg-serving-count">for <span class="rg-scaled-value">4</span></span></h1><p>Rescaled from <span class="rg-original-servings">2 servings</span>.</p></header>
                <div class="rg-recipe-block">
                  <table class="rg-table">
                    <tr>
                      <td class="rg-ingredient rg-border-left-sub-recipe rg-border-top-sub-recipe">
                        <span class="rg-quantity-with-conversions rg-scaled-value" tabindex="0">
                          200g<ul class="rg-quantity-conversions">
                            <li><sup>1</sup>&frasl;<sub>5</sub>kg</li>
                            <li>0.441lb</li>
                            <li>7.05oz</li>
                          </ul>
                        </span> spam
                      </td>
                      <td class="rg-step rg-border-right-sub-recipe rg-border-top-sub-recipe rg-border-bottom-sub-recipe" rowspan="2">fry</td>
                    </tr>
                    <tr><td class="rg-ingredient rg-border-left-sub-recipe rg-border-bottom-sub-recipe"><span class="rg-quantity-unitless rg-scaled-value">4</span> eggs</td></tr>
                  </table>
                </div><p>Ta-da!</p>
            """

                                             # noqa: E501
                                             ).lstrip())
コード例 #22
0
 def test_step_with_multiple_inputs_has_no_inferred_name(self) -> None:
     assert compile(["fry(spam, eggs)"]) == [
         Recipe(
             (Step(SVS("fry"),
                   (Ingredient(SVS("spam")), Ingredient(SVS("eggs")))), )),
     ]
コード例 #23
0
ファイル: test_html.py プロジェクト: mossblaser/recipe_grid
 def test_rowspan(self) -> None:
     assert (render_cell(
         Cell(
             Step(SVS("fry"), (Ingredient(SVS("spam")), )),
             rows=3,
         ), ) == '<td class="rg-step" rowspan="3">fry</td>')
コード例 #24
0
ファイル: test_html.py プロジェクト: mossblaser/recipe_grid
 def test_step(self) -> None:
     assert (render_cell(Cell(Step(
         SVS("fry"),
         (Ingredient(SVS("spam")), )))) == '<td class="rg-step">fry</td>')
コード例 #25
0
ファイル: test_html.py プロジェクト: mossblaser/recipe_grid
def test_render_step() -> None:
    assert render_step(Step(SVS("fry"), (Ingredient(SVS("spam")), ))) == "fry"
コード例 #26
0
 def _compile_step(self, ast_step: ast.Step) -> Step:
     return Step(
         description=compile_string(ast_step.name),
         inputs=tuple(
             self._compile_expr(ast_expr) for ast_expr in ast_step.inputs),
     )
コード例 #27
0

def test_normalise_output_name() -> None:
    # Just a sanity check
    assert normalise_output_name(SVS(" Foo ")) == normalise_output_name(
        SVS("fOo"))
    assert normalise_output_name(SVS(" Foo ")) != normalise_output_name(
        SVS("bAr"))


@pytest.mark.parametrize(
    "recipe_tree, exp",
    [
        # Workable cases
        (Ingredient(SVS("spam")), SVS("spam")),
        (Step(SVS("fry"), (Ingredient(SVS("spam")), )), SVS("spam")),
        # Can't name step with several inputs
        (Step(SVS("fry"),
              (Ingredient(SVS("spam")), Ingredient(SVS("eggs")))), None),
        # Can't name references
        (Reference(SubRecipe(Ingredient(SVS("spam")),
                             (SVS("spam"), )), 0), None),
        # Can't name sub recipes (they're already named!)
        (SubRecipe(Ingredient(SVS("spam")), (SVS("spam"), )), None),
    ],
)
def test_infer_output_name(recipe_tree: RecipeTreeNode,
                           exp: Optional[SVS]) -> None:
    assert infer_output_name(recipe_tree) == exp