feat: Add styles

main
bokuweb 2019-11-07 13:57:58 +09:00
parent 16ecf4ec8c
commit f5f089c54e
15 changed files with 278 additions and 40 deletions

View File

@ -55,6 +55,8 @@ impl BuildXML for ContentTypes {
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]

View File

@ -0,0 +1,34 @@
use crate::documents::BuildXML;
use crate::xml_builder::*;
pub struct Color {
val: String,
}
impl Color {
pub fn new(val: impl Into<String>) -> Color {
Color { val: val.into() }
}
}
impl BuildXML for Color {
fn build(&self) -> Vec<u8> {
XMLBuilder::new().color(&self.val).build()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_build() {
let c = Color::new("FFFFFF");
let b = c.build();
assert_eq!(str::from_utf8(&b).unwrap(), r#"<w:color w:val="FFFFFF" />"#);
}
}

View File

@ -19,9 +19,8 @@ impl DocDefaults {
impl BuildXML for DocDefaults {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
let run_property_default = self.run_property_default.build();
b.open_doc_defaults()
.add_child_buffer(&run_property_default)
.add_child(&self.run_property_default)
.close()
.build()
}

View File

@ -1,4 +1,5 @@
mod based_on;
mod color;
mod doc_defaults;
mod name;
mod next;
@ -10,6 +11,7 @@ mod style;
mod sz;
pub use based_on::*;
pub use color::*;
pub use doc_defaults::*;
pub use name::*;
pub use next::*;

View File

@ -25,6 +25,8 @@ impl BuildXML for ParagraphProperty {
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]

View File

@ -1,32 +1,45 @@
use super::Sz;
use super::{Color, Sz};
use crate::documents::BuildXML;
use crate::xml_builder::*;
pub struct RunProperty {
sz: Option<Sz>,
color: Option<Color>,
}
impl RunProperty {
pub fn new() -> RunProperty {
RunProperty { sz: None }
Default::default()
}
pub fn add_sz(mut self, sz: Sz) -> RunProperty {
self.sz = Some(sz);
pub fn add_sz(mut self, sz: usize) -> RunProperty {
self.sz = Some(Sz::new(sz));
self
}
pub fn add_color(mut self, color: &str) -> RunProperty {
self.color = Some(Color::new(color));
self
}
}
impl Default for RunProperty {
fn default() -> Self {
Self {
sz: None,
color: None,
}
}
}
impl BuildXML for RunProperty {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
let b = b.open_run_property();
let b = if let Some(sz) = &self.sz {
b.add_child_buffer(&sz.build())
} else {
b
};
b.close().build()
b.open_run_property()
.add_optional_child(&self.sz)
.add_optional_child(&self.color)
.close()
.build()
}
}
@ -40,11 +53,11 @@ mod tests {
#[test]
fn test_build() {
let c = RunProperty::new().add_sz(Sz::new(10));
let c = RunProperty::new().add_sz(10).add_color("FFFFFF");
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:rPr><w:sz w:val="10" /></w:rPr>"#
r#"<w:rPr><w:sz w:val="10" /><w:color w:val="FFFFFF" /></w:rPr>"#
);
}
}

View File

@ -16,9 +16,8 @@ impl RunPropertyDefault {
impl BuildXML for RunPropertyDefault {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
let run_property = self.run_property.build();
b.open_run_property_default()
.add_child_buffer(&run_property)
.add_child(&self.run_property)
.close()
.build()
}
@ -28,6 +27,8 @@ impl BuildXML for RunPropertyDefault {
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]

View File

@ -11,18 +11,14 @@ pub struct Style {
paragraph_property: ParagraphProperty,
}
impl Style {
pub fn new(
style_id: impl Into<String>,
name: impl Into<String>,
style_type: StyleType,
) -> Style {
let name = Name::new(name.into());
impl Default for Style {
fn default() -> Style {
let name = Name::new("");
let rpr = RunProperty::new();
let ppr = ParagraphProperty::new();
Style {
style_id: style_id.into(),
style_type,
style_id: "".to_owned(),
style_type: StyleType::Paragraph,
name,
run_property: rpr,
paragraph_property: ppr,
@ -30,22 +26,34 @@ impl Style {
}
}
impl Style {
pub fn new(
style_id: impl Into<String>,
name: impl Into<String>,
style_type: StyleType,
) -> Style {
let name = Name::new(name.into());
let default = Default::default();
Style {
style_id: style_id.into(),
style_type,
name,
..default
}
}
}
impl BuildXML for Style {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
let name = self.name.build();
let rpr = self.run_property.build();
let ppr = self.paragraph_property.build();
let based_on = BasedOn::new("Normal").build();
let next = Next::new("Normal").build();
let q_format = QFormat::new().build();
// Set "Normal" as default if you need change these values please fix it
b.open_style(self.style_type, &self.style_id)
.add_child_buffer(&name)
.add_child_buffer(&rpr)
.add_child_buffer(&ppr)
.add_child_buffer(&based_on)
.add_child_buffer(&next)
.add_child_buffer(&q_format)
.add_child(&self.name)
.add_child(&self.run_property)
.add_child(&self.paragraph_property)
.add_child(&BasedOn::new("Normal"))
.add_child(&Next::new("Normal"))
.add_child(&QFormat::new())
.close()
.build()
}

View File

@ -3,14 +3,17 @@ mod content_types;
mod doc_props;
mod elements;
mod rels;
mod styles;
mod xml_document;
pub(crate) use build_xml::*;
use crate::xml_builder::*;
use content_types::*;
use doc_props::*;
use elements::*;
use rels::*;
use styles::*;
pub(crate) struct Document {
content_type: ContentTypes,

View File

@ -39,6 +39,8 @@ mod tests {
use super::*;
use std::str;
#[cfg(test)]
use pretty_assertions::assert_eq;
#[test]
fn test_build() {

View File

@ -0,0 +1,59 @@
use crate::documents::BuildXML;
use crate::xml_builder::*;
use super::{DocDefaults, Style, StyleType};
pub struct Styles {
doc_defaults: DocDefaults,
styles: Vec<Style>,
}
impl Styles {
pub fn new() -> Styles {
Default::default()
}
pub fn add_style(mut self, style: Style) -> Self {
self.styles.push(style);
self
}
}
impl Default for Styles {
fn default() -> Self {
Self {
doc_defaults: DocDefaults::new(),
styles: vec![],
}
}
}
impl BuildXML for Styles {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
b.open_styles()
.add_child(&self.doc_defaults)
.add_children(&self.styles)
.close()
.build()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_build() {
let c = Styles::new().add_style(Style::new("Title", "TitleName", StyleType::Paragraph));
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15"><w:docDefaults><w:rPrDefault><w:rPr /></w:rPrDefault></w:docDefaults><w:style w:type="paragraph" w:styleId="Title"><w:name w:val="TitleName" /><w:rPr /><w:pPr /><w:basedOn w:val="Normal" /><w:next w:val="Normal" /><w:qFormat /></w:style></w:styles>"#
);
}
}

View File

@ -0,0 +1,28 @@
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
// i.e. <w:color ... >
pub(crate) fn color(mut self, val: &str) -> Self {
self.writer
.write(XmlEvent::start_element("w:color").attr("w:val", val))
.expect("should write to buf");
self.close()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_color() {
let b = XMLBuilder::new();
let r = b.color("2E74B5").build();
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:color w:val="2E74B5" />"#);
}
}

View File

@ -2,6 +2,7 @@
mod macros;
mod based_on;
mod color;
mod doc_defaults;
mod name;
mod next;
@ -13,6 +14,7 @@ mod style;
mod sz;
pub use based_on::*;
pub use color::*;
pub use doc_defaults::*;
pub use name::*;
pub use next::*;

View File

@ -6,7 +6,9 @@ mod declaration;
mod elements;
mod properties;
mod relationship;
mod styles;
use crate::BuildXML;
use std::str;
use xml::common::XmlVersion;
use xml::writer::{EmitterConfig, EventWriter, XmlEvent};
@ -50,12 +52,36 @@ impl XMLBuilder {
self.close()
}
pub(crate) fn add_child_buffer(mut self, buf: &[u8]) -> Self {
let text = str::from_utf8(buf).unwrap();
pub(crate) fn add_child<T>(mut self, child: &T) -> Self
where
T: BuildXML,
{
let buf = child.build();
let text = str::from_utf8(&buf).unwrap();
self.writer.write(text).expect("should write to buf");
self
}
pub(crate) fn add_optional_child<T>(mut self, child: &Option<T>) -> Self
where
T: BuildXML,
{
if let Some(c) = child {
self = self.add_child(c)
}
self
}
pub(crate) fn add_children<T>(mut self, children: &[T]) -> Self
where
T: BuildXML,
{
for c in children {
self = self.add_child(c);
}
self
}
// Close tag
pub(crate) fn close(mut self) -> Self {
self.writer

View File

@ -0,0 +1,57 @@
use std::fmt;
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
// Build w:style element
// i.e. <w:styles ... >
pub(crate) fn open_styles(mut self) -> Self {
self.writer
.write(
XmlEvent::start_element("w:styles")
.attr(
"xmlns:mc",
"http://schemas.openxmlformats.org/markup-compatibility/2006",
)
.attr(
"xmlns:r",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
)
.attr(
"xmlns:w",
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
)
.attr(
"xmlns:w14",
"http://schemas.microsoft.com/office/word/2010/wordml",
)
.attr(
"xmlns:w15",
"http://schemas.microsoft.com/office/word/2012/wordml",
)
.attr("mc:Ignorable", "w14 w15"),
)
.expect("should write to buf");
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_declaration() {
let b = XMLBuilder::new();
let r = b.open_styles().close().build();
assert_eq!(
str::from_utf8(&r).unwrap(),
r#"<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15" />"#
);
}
}