Exemplo n.º 1
0
 def test_from_unscaled_recipe_page(self, tmp_path: Path, link: str,
                                    exp_link: str) -> None:
     filename_to_asset_paths: MutableMapping[str, str] = {}
     assert (self.run(
         t("a", "Link", href=link),
         tmp_path=tmp_path,
         source=tmp_path / "foo" / "bar" / "unscaled.md",
         from_path="/categories/bar/unscaled.html",
         filename_to_asset_paths=filename_to_asset_paths,
     ) == t("a", "Link", href=exp_link))
     assert filename_to_asset_paths == {}
Exemplo n.º 2
0
    def test_valid(self, tmp_path: Path) -> None:
        (tmp_path / "bar.txt").open("w").write("foobar")

        assert (postprocess_html(
            t("a", "foo", href="bar.txt"),
            False,
            [
                partial(
                    embed_local_links_as_data_urls,
                    source=tmp_path / "foo.md",
                    root=tmp_path,
                ),
            ],
        ) == t("a", "foo", href="data:text/plain;base64,Zm9vYmFy"))
Exemplo n.º 3
0
 def test_from_scaled_category_page(
     self,
     tmp_path: Path,
     link: str,
     exp_link: str,
 ) -> None:
     filename_to_asset_paths: MutableMapping[str, str] = {}
     assert (self.run(
         t("a", "Link", href=link),
         tmp_path=tmp_path,
         source=tmp_path / "foo" / "bar" / "README.md",
         from_path="/serves123/bar/index.html",
         filename_to_asset_paths=filename_to_asset_paths,
     ) == t("a", "Link", href=exp_link))
     assert filename_to_asset_paths == {}
Exemplo n.º 4
0
def visit_pending_recipe_node(self: HTMLTranslator, node: nodes.Node) -> None:
    self.body.append(
        t(
            "div",
            "\n".join(
                render_recipe_tree(recipe_tree, node.id_prefix)
                for recipe_tree in node.recipe.scale(node.scale).recipe_trees),
            class_="rg-recipe-block",
        ))
Exemplo n.º 5
0
    def test_resolve_local_links_stage(
        self, input_path: Path, make_directory: MakeDirectoryFn
    ) -> None:
        h = HomePage.from_root_directory(
            make_directory({"foo/recipe.md": "# Recipe for 2", "foo/file.txt": "..."}),
        )

        filename_to_asset_paths: MutableMapping[Path, str] = {}
        stage = (
            h.scaled_categories[3]
            .subcategories[0]
            .recipes[0]
            .get_resolve_local_links_stage(
                source=input_path / "foo" / "recipe.md",
                source_to_page_paths={
                    input_path / "README.md": ("/categories/index.html", True),
                    input_path
                    / "foo"
                    / "recipe.md": ("/serves2/foo/recipe.html", True),
                },
                filename_to_asset_paths=filename_to_asset_paths,
            )
        )

        for href, exp_href in [
            # Check directory is correct
            ("recipe.md", "recipe.html"),
            # Check path is right (i.e. uses same number of servings
            ("../README.md", "../index.html"),
            # Check asset paths updated and asset dir is correct
            ("file.txt", "../../assets/foo/file.txt"),
        ]:
            assert postprocess_html(t("a", "foo", href=href), False, [stage]) == t(
                "a", "foo", href=exp_href
            )

        assert filename_to_asset_paths == {
            input_path / "foo" / "file.txt": "/assets/foo/file.txt",
        }

        # Check root is correctly set
        with pytest.raises(LinkToExternalFileError):
            postprocess_html(t("a", "foo", href="../../../foo.bar"), False, [stage])
Exemplo n.º 6
0
 def test_any_page_cases(
     self,
     tmp_path: Path,
     link: str,
     exp_link: str,
     exp_filename_to_asset_paths: Mapping[str, str],
     source: Path,
     from_path: str,
 ) -> None:
     filename_to_asset_paths: MutableMapping[str, str] = {}
     assert (self.run(
         t("a", "Link", href=link),
         tmp_path=tmp_path,
         source=tmp_path / source,
         from_path=from_path,
         filename_to_asset_paths=filename_to_asset_paths,
     ) == t("a", "Link", href=exp_link))
     assert filename_to_asset_paths == {
         tmp_path / file: path
         for file, path in exp_filename_to_asset_paths.items()
     }
Exemplo n.º 7
0
 def test_path_does_not_exist(self, tmp_path: Path) -> None:
     with pytest.raises(LinkToNonExistentFileError):
         postprocess_html(
             t("a", "foo", href="bar.txt"),
             False,
             [
                 partial(
                     embed_local_links_as_data_urls,
                     source=tmp_path / "foo.md",
                     root=tmp_path,
                 ),
             ],
         )
Exemplo n.º 8
0
 def test_path_outside_root(self, tmp_path: Path) -> None:
     with pytest.raises(LinkToExternalFileError):
         postprocess_html(
             t("a", "foo", href="../bar.txt"),
             False,
             [
                 partial(
                     embed_local_links_as_data_urls,
                     source=tmp_path / "foo.md",
                     root=tmp_path,
                 ),
             ],
         )
Exemplo n.º 9
0
    def test_ignore_external_or_page_local_links(self, tmp_path: Path,
                                                 url: str) -> None:
        html = t("a", "foo", href=url)

        assert (postprocess_html(
            html,
            False,
            [
                partial(
                    embed_local_links_as_data_urls,
                    source=tmp_path / "foo.md",
                    root=tmp_path,
                ),
            ],
        ) == html)
Exemplo n.º 10
0
    def render_heading(self, element: block.Heading) -> str:
        """
        Render headings, also capturing the first heading if it contains a
        serving count.
        """
        level = element.level
        text = self.render_children(element)  # type: ignore

        pre = ""  # To prepend before <h*> tag
        post = ""  # To append after </h*> tag
        attrs = ""  # Attributes to be inserted into the <h*> tag.

        # Capture the first title as recipe title. Ignore it if it isn't a H1
        # level title or if it contains HTML or a scaled value substitution
        # since we can't easily turn these into a plain text title.
        if self.first_heading and level == 1 and "<" not in text and "%" not in text:
            match = self.title_serving_count_pattern.search(text)
            if match is None:
                self.output.title = html.unescape(text.strip())
                attrs = ' class="rg-title-unscalable"'
            else:
                title = text[: match.start()]
                self.output.title = html.unescape(title.strip())
                self.output.servings = int(match["servings"])
                placeholder = generate_placeholder()
                self.output.scaled_value_strings[placeholder] = SVS(
                    int(match["servings"])
                )
                text = title + t(
                    "span",
                    match["preposition"] + placeholder,
                    class_="rg-serving-count",
                )
                attrs = ' class="rg-title-scalable"'
            pre = self.output.pre_title_placeholder = generate_placeholder()
            post = self.output.post_title_placeholder = generate_placeholder()

        self.first_heading = False

        return f"{pre}<h{level}{attrs}>{text}</h{level}>{post}\n"
Exemplo n.º 11
0
 def test_escape_attr_values(self) -> None:
     assert (t(
         "foo",
         bar="in 'quotes\" here") == '<foo bar="in \'quotes&quot; here"/>')
Exemplo n.º 12
0
 def test_multi_line_body(self) -> None:
     assert t("foo", "bar\nbaz") == "<foo>\n  bar\n  baz\n</foo>"
Exemplo n.º 13
0
 def test_single_line_body_with_trailing_newline(self) -> None:
     assert t("foo", "bar\n") == "<foo>\n  bar\n</foo>"
Exemplo n.º 14
0
 def test_single_line_body(self) -> None:
     assert t("foo", "bar") == "<foo>bar</foo>"
Exemplo n.º 15
0
 def test_with_body_and_attrs(self) -> None:
     assert t("foo", "", bar="baz") == '<foo bar="baz"></foo>'
     assert t("foo", "", bar="baz",
              quo="qux") == '<foo bar="baz" quo="qux"></foo>'
Exemplo n.º 16
0
 def test_empty_body(self) -> None:
     assert t("foo", "") == "<foo></foo>"
Exemplo n.º 17
0
 def test_dunderscore_to_hyphen_substitution(self) -> None:
     assert t("foo", data__foo="bar") == '<foo data-foo="bar"/>'
Exemplo n.º 18
0
 def test_underscore_postfix_removal(self) -> None:
     assert t("foo", class_="baz") == '<foo class="baz"/>'
Exemplo n.º 19
0
 def test_no_child_with_attrs(self) -> None:
     assert t("foo", bar="baz") == '<foo bar="baz"/>'
     assert t("foo", bar="baz", quo="qux") == '<foo bar="baz" quo="qux"/>'
Exemplo n.º 20
0
 def test_minimal_tag(self) -> None:
     assert t("foo") == "<foo />"
Exemplo n.º 21
0
    def render(self, scale: Union[int, float, Fraction] = 1) -> str:
        """
        Render this recipe scaled by a given factor.
        """
        html = self.html

        # Substitute scaled value strings
        for placeholder, svs in self.scaled_value_strings.items():
            html = html.replace(
                placeholder,
                render_scaled_value_string(svs.scale(scale)),
            )

        # Substitute scaled recipes
        id_prefix_index = 0
        for placeholder, recipe in self.recipe_placeholders.items():
            if recipe.follows is None:
                id_prefix_index += 1

            if id_prefix_index > 1:
                id_prefix = f"recipe{id_prefix_index}-"
            else:
                id_prefix = "recipe-"

            html = html.replace(
                placeholder,
                t(
                    "div",
                    "\n".join(
                        render_recipe_tree(recipe_tree, id_prefix)
                        for recipe_tree in recipe.scale(scale).recipe_trees
                    ),
                    class_="rg-recipe-block",
                ),
            )

        # Modify heading to include scaling info
        if (
            self.title is not None
            and self.pre_title_placeholder is not None
            and self.post_title_placeholder is not None
        ):
            html = html.replace(self.pre_title_placeholder, "<header>")
            post_title_text = ""
            if scale != 1:
                if self.servings is not None:
                    orig_servings = t(
                        "span",
                        f"{self.servings} serving{'s' if self.servings != 1 else ''}",
                        class_="rg-original-servings",
                    )
                    post_title_text = t("p", f"Rescaled from {orig_servings}.")
                else:
                    scale_str = t(
                        "span",
                        f"{render_number(scale)}&times;",
                        class_="rg-scaling-factor",
                    )
                    post_title_text = t("p", f"Scaled {scale_str}")
            html = html.replace(
                self.post_title_placeholder, f"{post_title_text}</header>"
            )

        return html