-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add optional support for lax rendering and parsing #492
base: master
Are you sure you want to change the base?
Conversation
In lax rendering mode, an undefined variable will simply be rendered as a `nil` value which will ultimately result in an empty string. In strict rendering mode, an undefined variable will continue to return an error.
In lax parsing mode, an undefined filter will simply return an internal noop filter. That filter will simply pass along the string to the next filter, if one is provided. In strict parsing mode, an undefined filter will continue to return an error.
#[derive(Clone)] | ||
pub enum ParseMode { | ||
Strict, | ||
Lax, | ||
} | ||
|
||
impl Default for ParseMode { | ||
fn default() -> Self { | ||
Self::Strict | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very general name that only covers filters. The name could imply tags, blocks, syntax errors as well.
Should we make this more specific?
Also, the line for what is parse vs render might be a bit fuzzy for a user that limiting these to just Render and Parse modes obscures the behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very general name that only covers filters. The name could imply tags, blocks, syntax errors as well.
Should we make this more specific?
Fair. I can update the name to be more specific.
Also, the line for what is parse vs render might be a bit fuzzy for a user that limiting these to just Render and Parse modes obscures the behavior.
Can you elaborate a bit more what you mean here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate a bit more what you mean here?
Is it required that filter lookups happen during parse or could it happen during runtime? At the moment, that is an implementation detail that can change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right that the implementation can change, but I personally think the way it's currently implemented is the correct behavior.
The way it's currently implemented allows you to store a template that are parsed once and reused multiple times. "Lazily" parsing the template means you delay errors that IMO should be handled when the template itself is created and in turn parsed.
Happy to explore alternative options if you think that's the right approach.
/// Sets the parse mode to lax. | ||
pub fn in_lax_mode(mut self) -> Self { | ||
self.mode = ParseMode::Lax; | ||
self | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd rather re-export the num and accept it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll update, I did it this way since there's only 2 options currently, 1 of which is the default. So exposing a function allowed us to now have to worry about exposing the enum to the user.
#[derive(Clone)] | ||
pub enum ParseMode { | ||
Strict, | ||
Lax, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, no docs on this
/// What mode to use when rendering. | ||
pub enum RenderingMode { | ||
/// Returns an error when a variable is not defined. | ||
Strict, | ||
/// Replaces missing variables with an empty string. | ||
Lax, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to my comments about ParseMode, I feel like this might be too general
#[derive(Clone)] | ||
pub enum ParseMode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this should also have Copy
, Debug
, PartialEq
and Eq
@@ -7,6 +7,14 @@ use crate::model::{Object, ObjectView, Scalar, ScalarCow, Value, ValueCow, Value | |||
use super::PartialStore; | |||
use super::Renderable; | |||
|
|||
/// What mode to use when rendering. | |||
pub enum RenderingMode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this should have Copy
, Clone
, Debug
, PartialEq
, Eq
, and Default
pub fn render_to(&self, writer: &mut dyn Write, globals: &dyn crate::ObjectView) -> Result<()> { | ||
self.render_to_with_mode(writer, globals, RenderingMode::Strict) | ||
} | ||
|
||
/// Renders an instance of the Template, using the given globals in lax mode. | ||
pub fn render_lax(&self, globals: &dyn crate::ObjectView) -> Result<String> { | ||
self.render_with_mode(globals, RenderingMode::Lax) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than having a bunch of different render funtions, should this be stored with the Parser and passed in when this is created?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually originally started that route but decided against it.
When stored on the parser that means you're unable to determine which mode you'd want to use after the parser is created. Every template that's parsed would be stuck in that rendering mode. People would in theory, need to then create two separate parsers to work around that limitation. Admittedly, I'm not sure how frequent people would ever need to change the rendering mode of a parser. I don't personally have a use case to argue that.
Another option is we could expose a function to set the rendering mode on the Template
instead. I'm not convinced that's a better UX, but probably a bit less confusing to most users who may use this solely in "strict" mode.
Following up on the issue I created here:
#490
This PR introduces two functional changes. The first being supporting a "lax" parsing mode, the second being a "lax" rendering mode. Each additional change extends the functionality, but does not change the default behavior.
Parsing Mode:
In lax parsing mode, an undefined filter will simply return an internal
noop filter. That filter will simply pass along the string to the next
filter, if one is provided.
In strict parsing mode, an undefined filter will continue to return an
error.
Rendering Mode:
In lax rendering mode, an undefined variable will simply be rendered as
a
nil
value which will ultimately result in an empty string.In strict rendering mode, an undefined variable will continue to return
an error.