yoshuawuyts / html

Type-safe HTML support for Rust
Apache License 2.0
247 stars 7 forks source link

Documentation could be clearer #53

Closed lindhe closed 1 year ago

lindhe commented 1 year ago

Hi!

I'm a beginner at Rust, and have been trying out this crate. Thought I'd pitch in with some feedback.

It was really easy for me to get going with something. I've got this pretty thing right now:

use html::root::Html;

fn main() {
    let html: Html = Html::builder()
        .head(|head| head.title(|title| title.text("FOO")))
        .body(|body| body.text("BAR"))
        .build();
    println!("{}", html);
}

But now, I feel like things are getting crowded so the next step would be for me to lift out the head definition into its own variable so I can separate things out a bit. I'm really not a skilled Rust programmer yet, so it's probably obvious to someone more experienced, but to me it's hard to figure out how to do that. I've been trying this, but it's obviously not working out:

use html::metadata::Head;
use html::root::Html;

fn main() {
    let head = Head::builder().title(|title| title.text("FOO"));

    let html: Html = Html::builder()
        .head(head)
        .body(|body| body.text("BAR"))
        .build();

    println!("{}", html);
}

It's clear that the .head() expects a closure, but I'm not sure what to do about that right now. :upside_down_face: But if I had some more examples and better documentation, I am sure I could figure it out given time.

There's really only two examples today:

use html::text_content::OrderedList;
let tree = OrderedList::builder()
    .list_item(|li| li.text("nori").class("cat"))
    .list_item(|li| li.text("chashu").class("cat"))
    .build();
let string = tree.to_string();
use html::text_content::OrderedList;
let mut ol = OrderedList::builder();
for name in ["hello", "world"] {
    ol.list_item(|li| li.text(name));
}
let tree = ol.build();

They are good examples, but the documentation would for sure be more useful if there were some other examples and more complex scenarios explained.

Cheers!

lindhe commented 1 year ago

I figured out my particular case! :)

use html::metadata::builders::TitleBuilder;
use html::root::Html;

fn make_title<'a>(t: &'a mut TitleBuilder) -> &mut TitleBuilder {
    t.text("FOO")
}

fn make_html() -> Html {
    Html::builder()
        .head(|h| h.title(make_title))
        .body(|body| body.text("HALLOJ"))
        .build()
}

fn main() {
    let html = make_html();
    println!("{}", html);
}

It's amazing how helpful the error messages in Rust are!

yoshuawuyts commented 1 year ago

Note also that each builder has a push method to push more elements into it. With that you can write:

use html::metadata::Head;
use html::root::Html;

fn main() {
    let head = Head::builder().title(|title| title.text("FOO"));

    let html: Html = Html::builder()
        .push(head)
        .body(|body| body.text("BAR"))
        .build();

    println!("{}", html);
}
lindhe commented 1 year ago

Are you sure? I tried running your example, and I get the following error:

$ cargo new foo     
     Created binary (application) `foo` package

$ cd foo 

$ cargo add html
    Updating crates.io index
      Adding html v0.6.0 to dependencies.
    Updating crates.io index

$ cat <<EOF > src/main.rs 
use html::metadata::Head;
use html::root::Html;

fn main() {
    let head = Head::builder().title(|title| title.text("FOO"));

    let html: Html = Html::builder()
        .push(head)
        .body(|body| body.text("BAR"))
        .build();

    println!("{}", html);
}
EOF

$ cargo check               
    Checking html-sys v0.4.0
    Checking html v0.6.0
    Checking foo v0.1.0 (/tmp/tmp.cOnf5AnmYX/foo)
error[E0277]: the trait bound `HtmlChild: From<&mut HeadBuilder>` is not satisfied
   --> src/main.rs:8:15
    |
8   |         .push(head)
    |          ---- ^^^^ the trait `From<&mut HeadBuilder>` is not implemented for `HtmlChild`
    |          |
    |          required by a bound introduced by this call
    |
    = help: the following other types implement trait `From<T>`:
              <HtmlChild as From<html::metadata::Head>>
              <HtmlChild as From<html::root::Body>>
    = note: required for `&mut HeadBuilder` to implement `Into<HtmlChild>`
note: required by a bound in `HtmlBuilder::push`
   --> /home/andreas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/html-0.6.0/src/generated/html.rs:671:16
    |
669 |         pub fn push<T>(&mut self, child_el: T) -> &mut Self
    |                ---- required by a bound in this associated function
670 |         where
671 |             T: Into<crate::generated::all::children::HtmlChild>,
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `HtmlBuilder::push`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `foo` (bin "foo") due to previous error

Screenshot from 2023-08-07 13-31-12

yoshuawuyts commented 1 year ago

Sorry, yeah it requires an extra .build() call on the argument passed.