Skip to content

Commit

Permalink
feat(expr): add TraversalBuilder (#121)
Browse files Browse the repository at this point in the history
  • Loading branch information
martinohmann committed Nov 6, 2022
1 parent 4020af9 commit 5e6daaa
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 4 deletions.
12 changes: 9 additions & 3 deletions README.md
Expand Up @@ -98,7 +98,7 @@ assert_eq!(body, expected);

## Serialization examples

A simple example to serialize some terraform configuration:
An example to serialize some terraform configuration:

```rust
use hcl::expr::Traversal;
Expand All @@ -111,12 +111,18 @@ let body = Body::builder()
.add_label("my-subscription")
.add_attribute((
"topic_arn",
Traversal::new(Variable::new("aws_sns_topic").unwrap(), ["my-topic", "arn"]),
Traversal::builder(Variable::new("aws_sns_topic").unwrap())
.attr("my-topic")
.attr("arn")
.build(),
))
.add_attribute(("protocol", "sqs"))
.add_attribute((
"endpoint",
Traversal::new(Variable::new("aws_sqs_queue").unwrap(), ["my-queue", "arn"]),
Traversal::builder(Variable::new("aws_sqs_queue").unwrap())
.attr("my-queue")
.attr("arn")
.build(),
))
.build(),
)
Expand Down
2 changes: 1 addition & 1 deletion src/expr/mod.rs
Expand Up @@ -22,7 +22,7 @@ pub use self::{
func_call::{FuncCall, FuncCallBuilder},
operation::{BinaryOp, BinaryOperator, Operation, UnaryOp, UnaryOperator},
template_expr::{Heredoc, HeredocStripMode, TemplateExpr},
traversal::{Traversal, TraversalOperator},
traversal::{Traversal, TraversalBuilder, TraversalOperator},
variable::Variable,
};
use crate::{format, Identifier, Number, Result, Value};
Expand Down
77 changes: 77 additions & 0 deletions src/expr/traversal.rs
Expand Up @@ -26,6 +26,83 @@ impl Traversal {
operators: operators.into_iter().map(Into::into).collect(),
}
}

/// Create a new `TraversalBuilder` for the given expression.
pub fn builder<T>(expr: T) -> TraversalBuilder
where
T: Into<Expression>,
{
TraversalBuilder {
expr: expr.into(),
operators: Vec::new(),
}
}
}

/// A builder for expression traversals.
///
/// It is constructed via the [`builder`][Traversal::builder] method of the [`Traversal`] type.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use hcl::expr::{Traversal, Variable};
///
/// let traversal = Traversal::builder(Variable::new("var")?)
/// .attr("some_array")
/// .index(0)
/// .build();
///
/// // Serializes as `var.some_array[0]`.
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct TraversalBuilder {
expr: Expression,
operators: Vec<TraversalOperator>,
}

impl TraversalBuilder {
/// Add an [attribute access operator][TraversalOperator::GetAttr] to the traversal chain.
pub fn attr<T>(mut self, ident: T) -> Self
where
T: Into<Identifier>,
{
self.operators
.push(TraversalOperator::GetAttr(ident.into()));
self
}

/// Add an [attribute splat operator][TraversalOperator::AttrSplat] to the traversal chain.
pub fn attr_splat<T>(mut self) -> Self {
self.operators.push(TraversalOperator::AttrSplat);
self
}

/// Add a [full splat operator][TraversalOperator::FullSplat] to the traversal chain.
pub fn full_splat<T>(mut self) -> Self {
self.operators.push(TraversalOperator::FullSplat);
self
}

/// Add an [index operator][TraversalOperator::Index] to the traversal chain.
pub fn index<T>(mut self, expr: T) -> Self
where
T: Into<Expression>,
{
self.operators.push(TraversalOperator::Index(expr.into()));
self
}

/// Consume `self` and return a `Traversal`.
pub fn build(self) -> Traversal {
Traversal {
expr: self.expr,
operators: self.operators,
}
}
}

/// The expression traversal operators that are supported by HCL.
Expand Down

0 comments on commit 5e6daaa

Please sign in to comment.