senny / sablon

Ruby Document Template Processor based on docx templates and Mail Merge fields.
MIT License
447 stars 128 forks source link

Conditionals: allow string comparism #165

Open ChrisKaun opened 3 years ago

ChrisKaun commented 3 years ago

We have a unique usecase for one of our customers who would like to display a string property dependent on it's value in different font-colors. This would require us to do something like this:

«car.color:if(val == 'green')»
  «=car.color» but marked in green
«car.color:elsif(val == 'red')»
  «=car.color» but marked in red
«car.color:endIf»

Of course it would be possible to create a getter method in rails that checks each color but since this is a really unique use case it wouldn't make any sense to hardcode this into our software logic.

senny commented 3 years ago

The idea behind the sablon template language is that templates should contain the least amount of knowledge possible. The reason is that they are hard to test and prone to errors when making changes. For that reason, such convenience operators are not provided. As you already deduced, the way to achieve this, would be by defining predicate methods on some object that you can check from the template.

stadelmanma commented 3 years ago

@ChrisKaun another good option might be to pre-process the context supplied by the user so you can streamline processing on the template side. I had several areas of complex logic and instead of trying to process that in the template I pre-processed stuff into several chunks of HTML and injected that into the document. One additional benefit of having most of the logic done outside of the template is that it lends itself to easier testing and validation.

ChrisKaun commented 3 years ago

The idea behind the sablon template language is that templates should contain the least amount of knowledge possible. The reason is that they are hard to test and prone to errors when making changes. For that reason, such convenience operators are not provided. As you already deduced, the way to achieve this, would be by defining predicate methods on some object that you can check from the template.

The problem with his approach is that each time a new color must be added the methods must be updated.

another good option might be to pre-process the context supplied by the user so you can streamline processing on the template side. I had several areas of complex logic and instead of trying to process that in the template I pre-processed stuff into several chunks of HTML and injected that into the document. One additional benefit of having most of the logic done outside of the template is that it lends itself to easier testing and validation.

If I understand that correctly this still would require changes in the pre-process logic each time the customer of ours requires a new color, which I would love to skip.

arvanasse commented 2 years ago

@ChrisKaun Using sablon within a rails framework, I've achieved what you're suggesting by wrapping the string in ActiveSupport::StringInquirer.

«car.color:if(green?)»
  «=car.color» but marked in green
«car.color:elsif(red?)»
  «=car.color» but marked in red
«car.color:endIf»