Add optional support for lax rendering and parsing#492
Add optional support for lax rendering and parsing#492RyanAmos wants to merge 2 commits intocobalt-org:masterfrom
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.
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.
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.
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.
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.
I think I'd rather re-export the num and accept it.
There was a problem hiding this comment.
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, | ||
| } |
| /// 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.
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.
I feel like this should also have Copy, Debug, PartialEq and Eq
| use super::Renderable; | ||
|
|
||
| /// What mode to use when rendering. | ||
| pub enum RenderingMode { |
There was a problem hiding this comment.
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.
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.
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
nilvalue which will ultimately result in an empty string.In strict rendering mode, an undefined variable will continue to return
an error.