Refactored project to use Builder pattern.
This commit is contained in:
@@ -1,115 +1,160 @@
|
||||
use crate::html::Render;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(crate) struct h1 {
|
||||
pub(crate) struct Heading {
|
||||
level: u8,
|
||||
id: String,
|
||||
text: String,
|
||||
classes: Vec<String>,
|
||||
}
|
||||
|
||||
impl Render for h1 {
|
||||
impl Render for Heading {
|
||||
fn render(&self) -> String {
|
||||
format!("<h1>{}</h1>", self.text)
|
||||
let classes = self.classes.join(" ");
|
||||
format!(
|
||||
"<h{} id=\"{}\" class=\"{}\">{}</h{}>",
|
||||
self.level, self.id, classes, self.text, self.level
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl h1 {
|
||||
pub(crate) fn new<T>(text: T) -> Self
|
||||
impl Heading {
|
||||
pub(crate) fn builder() -> HeadingBuilder {
|
||||
HeadingBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct HeadingBuilder {
|
||||
level: Option<u8>,
|
||||
id: Option<String>,
|
||||
text: Option<String>,
|
||||
classes: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl HeadingBuilder {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
level: None,
|
||||
id: None,
|
||||
text: None,
|
||||
classes: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn level(self, level: u8) -> Self {
|
||||
Self {
|
||||
level: Some(level),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn id<T>(self, id: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self { text: text.into() }
|
||||
Self {
|
||||
id: Some(id.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(crate) struct h2 {
|
||||
text: String,
|
||||
}
|
||||
|
||||
impl Render for h2 {
|
||||
fn render(&self) -> String {
|
||||
format!("<h2>{}</h2>", self.text)
|
||||
}
|
||||
}
|
||||
|
||||
impl h2 {
|
||||
pub(crate) fn new<T>(text: T) -> Self
|
||||
pub(crate) fn text<T>(self, text: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self { text: text.into() }
|
||||
Self {
|
||||
text: Some(text.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn classes<T>(self, classes: Vec<T>) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
classes: Some(classes.into_iter().map(|x| x.into()).collect()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> Heading {
|
||||
let level = self.level.unwrap_or(1);
|
||||
let id = self.id.unwrap_or(String::new());
|
||||
let text = self.text.unwrap_or(String::new());
|
||||
let classes = self.classes.unwrap_or(Vec::new());
|
||||
Heading {
|
||||
level,
|
||||
id,
|
||||
text,
|
||||
classes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(crate) struct link {
|
||||
pub(crate) struct Link {
|
||||
rel: String,
|
||||
href: String,
|
||||
}
|
||||
|
||||
impl Render for link {
|
||||
impl Render for Link {
|
||||
fn render(&self) -> String {
|
||||
format!("<link rel=\"{}\" href=\"{}\">", self.rel, self.href)
|
||||
}
|
||||
}
|
||||
|
||||
impl link {
|
||||
pub(crate) fn new<T, U>(rel: T, href: U) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
U: Into<String>,
|
||||
{
|
||||
Self {
|
||||
rel: rel.into(),
|
||||
href: href.into(),
|
||||
}
|
||||
impl Link {
|
||||
pub(crate) fn builder() -> LinkBuilder {
|
||||
LinkBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(crate) struct div {
|
||||
id: String,
|
||||
classes: Vec<String>,
|
||||
content: Vec<Box<dyn Render>>,
|
||||
pub(crate) struct LinkBuilder {
|
||||
rel: Option<String>,
|
||||
href: Option<String>,
|
||||
}
|
||||
|
||||
impl Render for div {
|
||||
fn render(&self) -> String {
|
||||
let classes = self.classes.join(" ");
|
||||
format!(
|
||||
"<div id=\"{}\" class=\"{}\">{}</div>",
|
||||
self.id,
|
||||
classes,
|
||||
self.content.render()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl div {
|
||||
pub(crate) fn new<T, U>(id: T, classes: Vec<U>) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
U: Into<String> + Clone,
|
||||
{
|
||||
impl LinkBuilder {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
classes: classes.iter().map(|x| x.clone().into()).collect(),
|
||||
content: vec![],
|
||||
rel: None,
|
||||
href: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn append_element(&mut self, element: impl Render + 'static) {
|
||||
self.content.push(Box::new(element));
|
||||
pub(crate) fn rel<T>(self, rel: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
rel: Some(rel.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn href<T>(self, href: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
href: Some(href.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> Link {
|
||||
let rel = self.rel.unwrap_or(String::new());
|
||||
let href = self.href.unwrap_or(String::new());
|
||||
Link { rel, href }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(crate) struct p {
|
||||
pub(crate) struct Paragraph {
|
||||
id: String,
|
||||
classes: Vec<String>,
|
||||
text: String,
|
||||
}
|
||||
|
||||
impl Render for p {
|
||||
impl Render for Paragraph {
|
||||
fn render(&self) -> String {
|
||||
let classes = self.classes.join(" ");
|
||||
format!(
|
||||
@@ -119,29 +164,72 @@ impl Render for p {
|
||||
}
|
||||
}
|
||||
|
||||
impl p {
|
||||
pub(crate) fn new<T, U, V>(id: T, classes: Vec<U>, text: V) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
U: Into<String> + Clone,
|
||||
V: Into<String>,
|
||||
{
|
||||
Self {
|
||||
id: id.into(),
|
||||
classes: classes.iter().map(|x| x.clone().into()).collect(),
|
||||
text: text.into(),
|
||||
}
|
||||
impl Paragraph {
|
||||
pub(crate) fn builder() -> ParagraphBuilder {
|
||||
ParagraphBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(crate) struct img {
|
||||
pub(crate) struct ParagraphBuilder {
|
||||
id: Option<String>,
|
||||
classes: Option<Vec<String>>,
|
||||
text: Option<String>,
|
||||
}
|
||||
|
||||
impl ParagraphBuilder {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
id: None,
|
||||
classes: None,
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn id<T>(self, id: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
id: Some(id.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn classes<T>(self, classes: Vec<T>) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
classes: Some(classes.into_iter().map(|x| x.into()).collect()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn text<T>(self, text: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
text: Some(text.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> Paragraph {
|
||||
let id = self.id.unwrap_or(String::new());
|
||||
let classes = self.classes.unwrap_or(Vec::new());
|
||||
let text = self.text.unwrap_or(String::new());
|
||||
Paragraph { id, classes, text }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Image {
|
||||
id: String,
|
||||
classes: Vec<String>,
|
||||
src: String,
|
||||
}
|
||||
|
||||
impl Render for img {
|
||||
impl Render for Image {
|
||||
fn render(&self) -> String {
|
||||
let classes = self.classes.join(" ");
|
||||
format!(
|
||||
@@ -151,30 +239,73 @@ impl Render for img {
|
||||
}
|
||||
}
|
||||
|
||||
impl img {
|
||||
pub(crate) fn new<T, U, V>(id: T, classes: Vec<U>, src: V) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
U: Into<String> + Clone,
|
||||
V: Into<String>,
|
||||
{
|
||||
Self {
|
||||
id: id.into(),
|
||||
classes: classes.iter().map(|x| x.clone().into()).collect(),
|
||||
src: src.into(),
|
||||
}
|
||||
impl Image {
|
||||
pub(crate) fn builder() -> ImageBuilder {
|
||||
ImageBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(crate) struct a {
|
||||
pub(crate) struct ImageBuilder {
|
||||
id: Option<String>,
|
||||
classes: Option<Vec<String>>,
|
||||
src: Option<String>,
|
||||
}
|
||||
|
||||
impl ImageBuilder {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
id: None,
|
||||
classes: None,
|
||||
src: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn id<T>(self, id: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
id: Some(id.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn classes<T>(self, classes: Vec<T>) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
classes: Some(classes.into_iter().map(|x| x.into()).collect()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn src<T>(self, src: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
src: Some(src.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> Image {
|
||||
let id = self.id.unwrap_or(String::new());
|
||||
let classes = self.classes.unwrap_or(Vec::new());
|
||||
let src = self.src.unwrap_or(String::new());
|
||||
Image { id, classes, src }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Anchor {
|
||||
id: String,
|
||||
classes: Vec<String>,
|
||||
href: String,
|
||||
text: String,
|
||||
}
|
||||
|
||||
impl Render for a {
|
||||
impl Render for Anchor {
|
||||
fn render(&self) -> String {
|
||||
let classes = self.classes.join(" ");
|
||||
format!(
|
||||
@@ -184,19 +315,78 @@ impl Render for a {
|
||||
}
|
||||
}
|
||||
|
||||
impl a {
|
||||
pub(crate) fn new<T, U, V, W>(id: T, classes: Vec<U>, href: V, text: W) -> Self
|
||||
impl Anchor {
|
||||
pub(crate) fn builder() -> AnchorBuilder {
|
||||
AnchorBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AnchorBuilder {
|
||||
id: Option<String>,
|
||||
classes: Option<Vec<String>>,
|
||||
href: Option<String>,
|
||||
text: Option<String>,
|
||||
}
|
||||
|
||||
impl AnchorBuilder {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
id: None,
|
||||
classes: None,
|
||||
href: None,
|
||||
text: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn id<T>(self, id: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
U: Into<String> + Clone,
|
||||
V: Into<String>,
|
||||
W: Into<String>,
|
||||
{
|
||||
Self {
|
||||
id: id.into(),
|
||||
classes: classes.iter().map(|x| x.clone().into()).collect(),
|
||||
href: href.into(),
|
||||
text: text.into(),
|
||||
id: Some(id.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn classes<T>(self, classes: Vec<T>) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
classes: Some(classes.into_iter().map(|x| x.into()).collect()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn href<T>(self, href: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
href: Some(href.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
pub(crate) fn text<T>(self, text: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
text: Some(text.into()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> Anchor {
|
||||
let id = self.id.unwrap_or(String::new());
|
||||
let classes = self.classes.unwrap_or(Vec::new());
|
||||
let href = self.href.unwrap_or(String::new());
|
||||
let text = self.text.unwrap_or(String::new());
|
||||
Anchor {
|
||||
id,
|
||||
classes,
|
||||
href,
|
||||
text,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user