7个版本 (破坏性更新)

使用旧Rust 2015

0.6.0 2019年6月6日
0.5.0 2017年11月30日
0.4.0 2017年11月7日
0.3.0 2017年11月6日
0.1.0 2017年11月4日

#26 in #construction

32 每月下载量

MIT 协议

61KB
1K SLoC

fluent_builder 构建状态 最新版本 文档

此crate提供了一种简单的API,用于通过直接使用值或使用一系列可变函数链来构造值。它旨在被其他构建器使用以保持构建的一致性。

有关更多详细信息,请参阅crate文档


lib.rs:

一个简单的构建器,用于构建或修改值。

此crate提供了一种简单的FluentBuilder结构。它提供了一些从给定源构造值或通过后续提供的默认值进行修改的标准行为。此crate旨在由其他构建器使用,而不是直接由用户使用。它特别适用于在构建器嵌套在其他构建器内时保持构建器的易用性。

此crate目前是为接受自我值的构建器设计的,而不是接受引用值。

用法

创建一个FluentBuilder并构建一个默认值

use fluent_builder::FluentBuilder;

let value = FluentBuilder::<String>::default()
.into_value(|| "A default value".to_owned());

assert_eq!("A default value", value);

可以直接向构建器提供值。在这种情况下,将使用该值而不是构建默认值

let value = FluentBuilder::<String>::default()
.value("A value".to_owned())
.into_value(|| "A default value".to_owned());

assert_eq!("A value", value);

可变方法将应用于具体值或构建的默认值

let value = FluentBuilder::<String>::default()
.fluent_mut(|s| s.push_str(" fluent2"))
.into_value(|| "A default value".to_owned());

assert_eq!("A default value fluent2", value);

堆叠流畅方法

每次调用.fluent时,默认情况下都会覆盖流畅方法,但可以使用泛型参数配置以在调用之间保持状态

use fluent_builder::{FluentBuilder, Stack};

let value = FluentBuilder::<String, Stack>::default()
.fluent_mut(|s| s.push_str(" fluent1"))
.fluent_mut(|s| s.push_str(" fluent2"))
.into_value(|| "A default value".to_owned());

assert_eq!("A default value fluent1 fluent2", value);

哪个选项最好取决于用例。对于类似集合的值,使用堆叠构建器可能更有意义。对于其他类型的值,使用覆盖构建器可能更有意义,因此它们是默认选择。使用泛型参数而不是某个值来控制是否堆叠流畅方法意味着您可以通过Rust的类型系统强制执行特定的样式。

有状态的构建器

流畅构建器还可以用于在构建过程中传递所需的状态

use fluent_builder::StatefulFluentBuilder;

#[derive(Debug, PartialEq, Eq)]
struct Builder {
required: String,
optional: Option<String>,
}

let value = StatefulFluentBuilder::<String, Builder>::from_seed("A required value".to_owned())
.fluent_mut("A required value".to_owned(), |b| {
if let Some(ref mut optional) = b.optional.as_mut() {
optional.push_str(" fluent1");
}
})
.into_value(|s| Builder {
required: s,
optional: Some("A default value".to_owned())
});

assert_eq!("A required value", value.required);
assert_eq!("A default value fluent1", value.optional.unwrap());

有状态的构建器还可以堆叠流畅的方法,而不是重写它们。API要求每个fluent调用都处理所需的状态

use fluent_builder::{StatefulFluentBuilder, Stack};

let value = StatefulFluentBuilder::<String, Builder, Stack>::from_seed("A required value".to_owned())
.fluent_mut("A required value".to_owned(), |s, b| {
b.required = s;
if let Some(ref mut optional) = b.optional.as_mut() {
optional.push_str(" fluent1");
}
})
.fluent_mut("A required value".to_owned(), |s, b| {
b.required = s;
if let Some(ref mut optional) = b.optional.as_mut() {
optional.push_str(" fluent2");
}
})
.into_value(|s| Builder {
required: s,
optional: Some("A default value".to_owned())
});

assert_eq!("A required value", value.required);
assert_eq!("A default value fluent1 fluent2", value.optional.unwrap());

在其他构建器内部

FluentBuilderStatefulFluentBuilder类型被设计用于在其他构建器内部使用,而不是直接使用。它们只是提供了一些关于分配和修改内部构建器的持续行为

use fluent_builder::{BoxedFluentBuilder, Stack};

#[derive(Default)]
struct RequestBuilder {
// Use a `FluentBuilder` to manage the inner `BodyBuilder`
body: BoxedFluentBuilder<BodyBuilder, Stack>,
}

#[derive(Default)]
struct BodyBuilder {
bytes: Vec<u8>,
}

impl<B> From<B> for BodyBuilder
where
B: AsRef<[u8]>
{
fn from(bytes: B) -> Self {
BodyBuilder {
bytes: bytes.as_ref().to_vec()
}
}
}

struct Request {
body: Body
}

struct Body(Vec<u8>);

impl RequestBuilder {
fn new() -> Self {
RequestBuilder {
body: BoxedFluentBuilder::default(),
}
}

// Accept any type that can be converted into a `BodyBuilder`
// This will override any previously stored state or default
fn body<B>(mut self, body: B) -> Self
where
B: Into<BodyBuilder>
{
self.body = self.body.value(body.into());
self
}

// Mutate some `BodyBuilder` without having to name its type
// If there's no previously supplied concrete value then some
// default will be given on `build`
fn body_fluent<F>(mut self, body: F) -> Self
where
F: Fn(BodyBuilder) -> BodyBuilder + 'static
{
self.body = self.body.fluent(body).boxed();
self
}

fn build(self) -> Request {
// Get a `Body` by converting the `FluentBuilder` into a `BodyBuilder`
let body = self.body.into_value(|| BodyBuilder::default()).build();

Request {
body: body
}
}
}

impl BodyBuilder {
fn append(mut self, bytes: &[u8]) -> Self {
self.bytes.extend(bytes);
self
}

fn build(self) -> Body {
Body(self.bytes)
}
}

// Use a builder to construct a request using fluent methods
let request1 = RequestBuilder::new()
.body_fluent(|b| b.append(b"some"))
.body_fluent(|b| b.append(b" bytes"))
.build();

// Use a builder to construct a request using a given value
let request2 = RequestBuilder::new()
.body(b"some bytes")
.build();

assert_eq!(request1.body.0, request2.body.0);

这看起来像是很多样板代码,但在你有大量可能嵌套的构建器并需要保持它们一致时很有用。上述构建器除了使用FluentBuilder之外,并没有什么特别之处。

无运行时依赖