Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
Curlybars
https://github.com/zendesk/curlybars
Admin
Handlebars.js compatible templating library in Ruby
Tokens:
8,152
Snippets:
72
Trust Score:
8.1
License:
Apache-2.0
Update:
1 year ago
Context
Chat
Benchmark
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Handlebars Context Example for Comparison Source: https://github.com/zendesk/curlybars/blob/main/docs/presenters.md This JavaScript object demonstrates a typical Handlebars context structure, used to illustrate how Curlybars root presenters provide the top-level data for template rendering. ```javascript { amount: "100", date: "August 22th, 2017", recipient: { name: "John Venturini" } } ``` -------------------------------- ### Curlybars Improved Data Access with 'with' Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example demonstrates how the 'with' construct simplifies data access by setting a temporary context. It shows how repetitive prefixes can be removed, making the template cleaner and more readable. ```hbs {{#with recipient.details}} <div> <p>Billing address: {{billing_address}}</p> <p>Delivery address: {{delivery_address}}</p> <p>Company name: {{company.name}}</p> </div> {{/with}} ``` -------------------------------- ### Create Handlebars Template for Invoice Details Source: https://github.com/zendesk/curlybars/blob/main/README.md Example Handlebars template (.hbs) for displaying invoice details, including amount, date, and recipient's name, demonstrating basic path resolution within Curlybars. ```hbs {{! app/views/invoices/show.html.hbs }} <h1>Amount #{{amount}} (issued on {{date}})</h1> <h2>To: {{recipient.name}}</h2> ``` -------------------------------- ### Analyzing Curlybars Templates with Ruby AST Visitor Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md Provides a Ruby example demonstrating how to traverse a Curlybars template's Abstract Syntax Tree (AST) using a custom visitor. The 'DescriptionVisitor' checks for the presence of a specific path ('description') in the template without rendering it. ```ruby class DescriptionVisitor < Curlybars::Visitor def visit_path(node) if node.path == 'description' self.context = true end super end end source = <<-HBS There are {{recipient.entries.length}} entries in this invoice. <ul> {{#each recipient.entries}} <li>{{description}} -- ${{amount}}</li> {{/each}} </ul> HBS contains_description = Curlybars.visit(DescriptionVisitor.new(false), source) contains_description == true # true ``` -------------------------------- ### Example Curlybars Root Presenter Implementation Source: https://github.com/zendesk/curlybars/blob/main/docs/presenters.md This Ruby code defines a ShowPresenter for an Invoice model, extending Curlybars::Presenter. It showcases how to declare the presented model, whitelist methods using allow_methods for literal values and nested PORO presenters, and implement data retrieval methods. ```ruby # app/presenters/invoices/show_presenter.rb class Invoices::ShowPresenter < Curlybars::Presenter presents :invoice allow_methods :amount, :date, recipient: RecipientPresenter def amount @invoice.amount end def date @invoice.created_at.to_formatted_s(:short) end def recipient RecipientPresenter.new(@invoice.recipient) end end ``` -------------------------------- ### Curlybars Accessing Parent Contexts with '../' in 'with' Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example demonstrates how to use the '../' notation within a 'with' block to access properties from a parent context. This allows for flexible navigation up the data hierarchy even when a scope has been narrowed. ```hbs {{#with recipient.details}} <div> {{../details.billing_address}} ... </div> {{/with}} ``` -------------------------------- ### Basic Curlybars Template: Text-only Example Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet demonstrates a basic Curlybars template consisting solely of verbatim text. An empty template or one containing only static text is considered valid in Curlybars, rendering content as is without any dynamic expressions. ```hbs <h1>Invoice</h1> <p>Some details on the invoice</p> ``` -------------------------------- ### Example Curlybars PORO Presenter Implementation Source: https://github.com/zendesk/curlybars/blob/main/docs/presenters.md This Ruby code demonstrates a RecipientPresenter, a Plain Old Ruby Object (PORO) that extends Curlybars::MethodWhitelist. It illustrates how to whitelist methods like name and initialize the presenter with a data object, providing a clean interface for template access. ```ruby # app/presenters/recipient_presenter.rb class RecipientPresenter extend Curlybars::MethodWhitelist allow_methods :name def initialize(recipient) @recipient = recipient end def name @recipient.name end end ``` -------------------------------- ### Basic Curlybars Template: Including an Expression Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example shows how to incorporate dynamic logic into a Curlybars template using expressions. Expressions are enclosed in double curly brackets {{ }} and are used to display data, such as {{recipient.name}}. ```hbs <h1>Invoice</h1> <p>Some details on the invoice</p> {{recipient.name}} ``` -------------------------------- ### Curlybars Template: Conditional Rendering with `unless-else` Block Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example demonstrates the {{#unless ...}}{{else}}{{/unless}} block, providing an alternative to `if-else` for conditional rendering. It renders the first block when the condition is false, and the `else` block when the condition is true. ```hbs <h1>Invoice</h1> <p> {{#unless has_different_delivery_address}} The delivery and billing addresses are the same. {{else}} The delivery address is different from the billing address. {{/unless}} </p> <p>Recipient: {{recipient.name}}</p> ``` -------------------------------- ### Displaying Collection Length in Curlybars Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md Demonstrates accessing the implicit 'length' property of a collection to display its size. This example shows how to use 'recipient.entries.length' directly in the template. ```hbs There are {{recipient.entries.length}} entries in this invoice. <ul> {{#each recipient.entries}} <li>{{description}} -- ${{amount}}</li> {{/each}} </ul> ``` -------------------------------- ### Define Generic Collection Helper in Presenters (Ruby) Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md This Ruby example shows how to define generic collection helpers within root or Plain Old Ruby Object (PORO) presenters. It demonstrates the use of `allow_methods` to whitelist a helper, `do_something`, specifying it as a generic helper that infers its return type. ```ruby class CustomPresenter extend Curlybars::MethodWhitelist allow_methods do_something: [:helper, [Curlybars::Generic]] end ``` -------------------------------- ### Defining and Using Presenter Helpers in Curlybars Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md Explains how to define a presenter helper in Ruby that returns a specific type of presenter, specified via `allow_methods` with the presenter class. The example demonstrates a `translate_article` helper returning an `ArticlePresenter`, useful for manipulating presented objects in `#with` statements. ```ruby class ArticlePresenter extend Curlybars::MethodWhitelist allow_methods translate_article: [:helper, ArticlePresenter] def transform_articles(locale) ArticlePresenter.new(Article.translate(article, locale)) end end ``` ```hbs {{#with (translate_article "en-US")}} {{author.name}} {{/with}} ``` -------------------------------- ### Handle invalid signature: Curlybars `validate.invalid_signature` exception Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This exception is raised when invoking a method that is allowed as a leaf (i.e., it doesn't accept any arguments or options) but is called with arguments or options. The Ruby example shows a `UserPresenter` with a simple `name` method, while the HBS example demonstrates an invalid call that triggers the exception. ```Ruby class UserPresenter allow_methods :name def name ... end end ``` ```HBS {{! this will raise the exception }} {{name 'argument' option='value'}} ``` -------------------------------- ### Curlybars Whitespace Trimming with Tilde (~) Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example shows how to use the tilde character (~) within Curlybars expressions to trim leading and trailing whitespace from the rendered output. It effectively removes spaces, newlines, tabs, and other blank characters. ```hbs <p class="{{#if highlighted~}} highlight {{~/if}}"> ... </p> ``` ```hbs <p class="highlight"> ... </p> ``` -------------------------------- ### Using Nested Subexpressions in Curlybars Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md Shows an example of nested subexpressions in Curlybars, where the result of an inner helper ('dc "search_text"') is passed as an argument to an outer helper ('lowercase'), and then to a third helper ('search'). ```hbs {{search placeholder=(lowercase (dc "search_text"))}} ``` -------------------------------- ### Implementing Block Helpers in Curlybars with Ruby Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md Demonstrates how to create a block helper in Curlybars using Ruby, where the helper method invokes `yield` to render the content within its block. The example shows a `form` helper that wraps its block content in an HTML form tag, allowing for dynamic HTML generation. ```hbs {{#form '/documents/new' class='red'}} <input type="text" name="body"> {{/form}} ``` ```ruby def form(action, options) klass = options[:class] "<form class='#{klass}' action='#{action}'>#{yield}</form>" end ``` -------------------------------- ### Curlybars Repetitive Data Access Without 'with' Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example demonstrates a common scenario where deep data paths lead to repetitive prefixes in a Curlybars template. It highlights how accessing multiple properties from a nested object can make the template code cluttered. ```hbs <div> <p>Billing address: {{recipient.details.billing_address}}</p> <p>Delivery address: {{recipient.details.delivery_address}}</p> <p>Company name: {{recipient.details.company.name}}</p> </div> ``` -------------------------------- ### Curlybars Template: Conditional Rendering with `unless` Block Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example demonstrates the {{#unless ...}} block for conditional rendering in Curlybars. Unlike `if`, the content within an `unless` block is rendered only when the given expression evaluates to a falsy value. ```hbs <h1>Invoice</h1> {{#unless has_different_delivery_address}} <p>The delivery and billing addresses are the same.</p> {{/unless}} <p>Recipient: {{recipient.name}}</p> ``` -------------------------------- ### Invalid Curlybars Syntax: Nested Expressions Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet illustrates an example of invalid syntax in Curlybars templates. Nesting a pair of curly brackets within another pair, such as {{ {{ ... }} }}, is not permitted and will result in a parsing error. ```hbs <h1>Invoice</h1> <p>Some details on the invoice</p> {{ {{ ... }} }} ``` -------------------------------- ### Curlybars Validation Error: Calling Non-Partial as Partial Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This example demonstrates the `validate.not_a_partial` exception, which occurs when a path is invoked as a partial but is not declared as such in the presenter's `allow_method` definition. Calling `{{> menu}}` is valid if `menu` is a partial, but `{{menu}}` will raise this error if `menu` is not configured as a partial. ```ruby class NavigationPresenter allow_method menu: :partial def menu ... end end ``` ```hbs {{! this will NOT raise the exception }} {{> menu}} {{! this will raise the exception }} {{menu}} ``` -------------------------------- ### Defining and Using Collection Helpers in Curlybars Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md Details how to define a collection helper in Ruby that returns a specific kind of collection, specified via `allow_methods` with an array type. The example shows a `transform_articles` helper returning a collection of `ArticlePresenter` instances, useful for manipulating collections in `#each` statements. ```ruby class ArticlePresenter extend Curlybars::MethodWhitelist allow_methods transform_articles: [:helper, [ArticlePresenter]] def transform_articles(articles, options) articles.map { |article| transform_article(article) } end end ``` ```hbs {{#each (slice (transform_articles articles) 0 4)}} {{author.name}} {{/each}} ``` -------------------------------- ### Curlybars Validation Error: Calling Non-Helper as Helper Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This example demonstrates the `validate.not_a_helper` exception. It is raised when a path not explicitly marked as a helper in the `allow_methods` declaration is invoked with arguments. Calling `helper` is valid, but `not_a_helper` will cause this error if it's not defined as a helper. ```ruby class InvoicePresenter allow_methods :not_a_helper, helper: :helper def not_a_helper ... end def helper ... end end ``` ```hbs {{! this will NOT raise the exception }} {{helper 'argument'}} {{! this will raise the exception }} {{not_a_helper 'argument'}} ``` -------------------------------- ### Curlybars Template: Accessing Nested Data with Paths Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example demonstrates how Curlybars templates use dot-based notation, or 'paths', to access values nested within a root presenter. The expression {{recipient.name}} invokes methods on presenter objects to retrieve and display the recipient's name. ```hbs <h1>Invoice</h1> <p>Recipient: {{recipient.name}}</p> ``` -------------------------------- ### Handle non-presenter context: Curlybars `render.context_is_not_a_presenter` exception Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This exception occurs when a language construct expecting a presenter receives a path that does not evaluate to a presenter. The Ruby `ArticlePresenter` allows `title` (a string) and `author` (a presenter). The HBS example demonstrates that `{{#with author}}` is valid, but `{{#with title}}` raises the exception because `title` is not a presenter. ```Ruby class ArticlePresenter allow_methods :title, author: AuthorPresenter def title ... end def author ... end end ``` ```HBS {{! this will NOT raise the exception }} {{#with author}} ... {{/with}} {{! this will raise the exception }} {{#with title}} ... {{/with}} ``` -------------------------------- ### Curlybars Template: Commenting Out Code Blocks Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This example shows how to comment out blocks of Curlybars code using the {{!-- ... --}} syntax. This type of comment is suitable for disabling sections of template logic, even spanning multiple lines, without affecting the rendered output. ```hbs {{! This template aims to show details of an invoice }} <h1>Invoice</h1> <p>Some details on the invoice</p> {{!-- I want to comment out the following code: {{ ... some Curlybars expressions }} --}} ``` -------------------------------- ### Curlybars Validation Error: Invalid Block Helper Declaration Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This example illustrates the `validate.invalid_block_helper` exception. It occurs when a block helper is declared with an invalid type (e.g., `:other`) that is neither a leaf nor a presenter. Such a declaration prevents the block helper from being used correctly. ```ruby class UserPresenter allow_methods block_helper: :other end ``` ```hbs {{! this will raise the exception }} {{#block_helper}} ... {{/block_helper}} ``` -------------------------------- ### Curlybars Validation Error: Iterating Over Non-Presenter Collection Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This example demonstrates the `validate.not_a_presenter_collection` exception. It is raised when a construct expecting a collection of presenters (like `#each`) is provided a path that is not declared as such. Iterating over `comments` is valid, but iterating over `title` will cause this error if `title` is not a collection of presenters. ```ruby class ArticlePresenter allow_methods :title, comments: [CommentPresenter] def title ... end def comments ... end end ``` ```hbs {{! this will NOT raise the exception }} {{#each comments}} ... {{/each}} {{! this will raise the exception }} {{#each title}} ... {{/each}} ``` -------------------------------- ### Curlybars Validation Error: Using Non-Presenter in Presenter Context Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This example illustrates the `validate.not_a_presenter` exception. It occurs when a language construct expecting a presenter (like `#with`) is given a path that, according to its `allow_method` declaration, does not evaluate to a presenter. Using `#with author` is valid, but `#with title` will raise an error if `title` is not a presenter. ```ruby class ArticlePresenter allow_methods :title, author: AuthorPresenter def title ... end def author ... end end ``` ```hbs {{! this will NOT raise the exception }} {{#with author}} ... {{/with}} {{! this will raise the exception }} {{#with title}} ... {{/with}} ``` -------------------------------- ### Handle non-array-of-presenters context: Curlybars `render.context_is_not_an_array_of_presenters` exception Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This exception occurs when a language construct expecting a collection of presenters receives a path that does not evaluate to such a collection. The Ruby `ArticlePresenter` allows `title` (a string) and `comments` (an array of presenters). The HBS example shows that `{{#each comments}}` is valid, but `{{#each title}}` raises the exception because `title` is not an array of presenters. ```Ruby class ArticlePresenter allow_methods :title, comments: [CommentPresenter] def title ... end def comments ... end end ``` ```HBS {{! this will NOT raise the exception }} {{#each comments}} ... {{/each}} {{! this will raise the exception }} {{#each title}} ... {{/each}} ``` -------------------------------- ### Handle unallowed path: Curlybars `validate.unallowed_path` exception Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This exception occurs when a path is not allowed according to the presenter's `allow_methods` definition. The Ruby code defines a `UserPresenter` allowing only the `name` method. The HBS examples show a valid path (`user.name`) and an invalid one (`user.foo`) that raises the exception. The exception's metadata payload includes 'path' and 'step' attributes. ```Ruby class UserPresenter allow_methods :name def name ... end end ``` ```HBS {{! this will NOT raise the exception }} {{ user.name }} {{! this will raise the exception }} {{ user.foo }} ``` -------------------------------- ### Curlybars Validation Error: Calling Non-Leaf Method as Leaf Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This example illustrates the `validate.not_a_leaf` exception. It occurs when a language construct expecting a terminal output (a 'leaf' method) is given a path that is not declared as such. Calling `link` as a helper is valid, but calling `comments` (which is a collection) as a leaf will raise this error. ```ruby class InvoicePresenter allow_methods link: :helper, entries: [EntryPresenter] def link(url) ... end def entries ... end end ``` ```hbs {{! this will NOT raise the exception }} {{link 'http://test.com/cat.jpg'}} {{! this will raise the exception }} {{comments 'http://test.com/cat.jpg'}} ``` -------------------------------- ### Handle unallowed subpath: Curlybars `render.unallowed_path` exception Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This exception occurs when a path contains an unallowed subpath. The Ruby code defines `ArticlePresenter` allowing `author` and `AuthorPresenter` allowing `name`. The HBS example shows that `{{author.name}}` is valid, but `{{author.surnames}}` raises the exception because `surnames` is not an allowed method on `AuthorPresenter`. The exception's metadata payload includes the 'meth' attribute. ```Ruby class ArticlePresenter allow_methods :author def author ... end end class AuthorPresenter allow_methods :name def name ... end end ``` ```HBS {{! this will NOT raise the exception }} {{author.name}} {{! this will raise the exception }} {{author.surnames}} ``` -------------------------------- ### Handle excessive nesting: Curlybars `render.traverse_too_deep` exception Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This exception occurs when the template contains too many nested context-pushing elements (e.g., `#with`). The maximum allowed depth is controlled by the `nesting_limit` configuration parameter, which defaults to 10. The HBS example assumes a `nesting_limit` of 2, showing that two levels of nesting are allowed, but three levels will raise the exception. ```HBS {{! let's assume that nesting_limit is set to 2... }} {{! this will NOT raise the exception }} {{#with this}} {{#with this}} {{/with}} {{/with}} {{! this will raise the exception }} {{#with this}} {{#with this}} {{#with this}} {{/with}} {{/with}} {{/with}} ``` -------------------------------- ### Handle invalid helper signature: Curlybars `render.invalid_helper_signature` exception Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This exception occurs when a helper is called with an invalid signature. The Ruby `ArticlePresenter` defines two helper methods: `bad_signature_helper` (which uses a keyword argument `context:`) and `correct_signature_helper` (which uses a positional argument `context`). The HBS example demonstrates that calling `correct_signature_helper` is valid, while calling `bad_signature_helper` raises the exception due to its invalid signature. ```Ruby class ArticlePresenter allow_methods :bad_signature_helper, :correct_signature_helper def bad_signature_helper(context:) ... end def correct_signature_helper(context) ... end end ``` ```HBS {{! this will NOT raise the exception }} {{correct_signature_helper 'context'}} {{! this will raise the exception }} {{bad_signature_helper 'context'}} ``` -------------------------------- ### Implement Invoices Controller Show Action in Rails Source: https://github.com/zendesk/curlybars/blob/main/README.md Rails controller action for the InvoicesController, demonstrating how to instantiate Recipient and Invoice models to prepare data for a view. ```Ruby # app/controllers/invoices_controller.rb class InvoicesController < ApplicationController def show recipient = Recipient.new(name: "John Venturini") @invoice = Invoice.new(amount: 100, recipient: recipient) end end ``` -------------------------------- ### Curlybars Configuration Properties Source: https://github.com/zendesk/curlybars/blob/main/docs/configuration.md Detailed API documentation for the configuration properties available within the `Curlybars.configure` block. ```APIDOC Curlybars.configure: Properties: presenters_namespace: Type: String Default: '' Description: Defines a global namespace for all presenters. When set, Curlybars will look for presenters within this namespace (e.g., 'Experimental::Invoices::ShowPresenter'). nesting_limit: Type: Integer Default: 10 Description: Sets the maximum allowed nesting level for `with` or `each` blocks in a template. If a template exceeds this limit, `Curlybars::Error::Render` will be raised. traversing_limit: Type: Integer Default: 10 Description: Sets the maximum number of steps allowed during a path traversal (e.g., `a.b.c` has 3 steps). If a path with more steps than allowed is encountered, `Curlybars::Error::Render` will be raised. output_limit: Type: Integer (bytes) Default: 1.megabyte Description: Sets the maximum allowed size of the rendered output. A reasonable limit provides better guarantees on system stability and controls generated response traffic. If the output limit is reached during rendering, `Curlybars::Error::Render` will be raised. rendering_timeout: Type: Integer (seconds) Default: 10.seconds Description: Sets a timeout on the rendering time. This constraint provides better guarantees on system stability. If a rendering takes longer than the configured threshold, `Curlybars::Error::Render` will be raised. global_helpers_provider_classes: Type: Array<Class> Default: [] Description: Allows registration of global helper provider classes. Refer to the `docs/helpers.md` for more details on global helpers. cache: Type: Proc Default: ->(cache_key, &block) { block.call } Description: A callable that enables caching of PORO presenters with `{{#each}}`. It should respond to `call` with one argument (`cache_key`) and a block. The callable is expected to return a cached value if present, otherwise call the block and store the result. To integrate with Rails, set this value to `Rails.cache.method(:fetch)`. ``` -------------------------------- ### Curlybars 'with' Construct Basic Syntax Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet provides the fundamental syntax for the Curlybars 'with' construct. It explains that 'with' takes a prefix path as a parameter, which then serves as the base context for expressions within its block. ```hbs {{#with <prefix>}} ... {{/with}} ``` -------------------------------- ### Registering Global Helper Provider Classes in Curlybars (Ruby) Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md Shows how to configure Curlybars to recognize and use global helper classes. By adding a PORO class to `config.global_helpers_provider_classes`, all its allowed methods are assumed to be helpers and become universally available in templates. ```ruby Curlybars.configure do |config| config.global_helpers_provider_classes = [ Helpers::GlobalHelper ] end ``` -------------------------------- ### Define Curlybars Helper in Ruby Presenter Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md This Ruby snippet shows how to define a helper method, `excerpt`, within a `Curlybars::Presenter`. It demonstrates allowing the helper via `allow_methods` and implementing the helper logic to truncate text based on a `max` option. The `description` method is also shown, illustrating how presenter methods provide data to templates. ```ruby # app/presenters/invoices/show_presenter.rb class Invoices::ShowPresenter < Curlybars::Presenter presents :invoice allow_methods :amount, :date, :description, recipient: RecipientPresenter, # allow `excerpt` and declare it as helper excerpt: :helper ... def description @invoice.description end # helper implementation def excerpt(context, options) max = options.fetch(:max, 120) context.to_s.truncate(max) end end ``` -------------------------------- ### Curlybars Template Validation API Reference Source: https://github.com/zendesk/curlybars/blob/main/docs/presenters.md API documentation for the Curlybars template validation methods, `Curlybars.valid?` and `Curlybars.validate`, which allow pre-checking templates for errors before rendering. These methods accept template content and a root presenter class. ```APIDOC Curlybars.valid?(template_content: String, root_presenter_class: Class) -> Boolean Parameters: template_content: The template content as a string. root_presenter_class: The root presenter class with which the template will be rendered. Returns: true if no errors are found upon rendering, false otherwise. ``` ```APIDOC Curlybars.validate(template_content: String, root_presenter_class: Class) -> Array<Curlybars::Error::Validate> Parameters: template_content: The template content as a string. root_presenter_class: The root presenter class with which the template will be rendered. Returns: An array of Curlybars::Error::Validate instances. An empty array indicates no errors. Related Errors: Curlybars::Error::Lex: Raised for malformed strings during lexing (e.g., 'string" with different quotes). Curlybars::Error::Render: Raised for unallowed paths during rendering. ``` -------------------------------- ### Handling Empty Collections with Curlybars 'each' and 'else' Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md Illustrates how to provide an alternative block of content using 'else' within an 'each' helper, which is rendered when the collection being iterated over is empty. ```hbs ... <ul> {{#each recipient.entries}} <li>{{description}} -- ${{amount}}</li> {{else}} There are no entries to show for this invoice. {{/each}} </ul> ``` -------------------------------- ### Define a Root Presenter for Invoices in Curlybars (Ruby) Source: https://github.com/zendesk/curlybars/blob/main/README.md This Ruby snippet defines `Invoices::ShowPresenter`, a root presenter extending `Curlybars::Presenter`. It whitelists `amount`, `date`, and `recipient` methods using `allow_methods`, making them available to Curlybars templates. The `recipient` method returns an instance of `RecipientPresenter` for nested data access. ```ruby class Invoices::ShowPresenter < Curlybars::Presenter presents :invoice allow_methods :amount, :date, recipient: RecipientPresenter def amount @invoice.amount end def date @invoice.created_at.to_formatted_s(:short) end def recipient RecipientPresenter.new(@invoice.recipient) end end ``` -------------------------------- ### Configure Curlybars Presenters Namespace in Ruby Source: https://github.com/zendesk/curlybars/blob/main/docs/configuration.md This snippet shows how to define a global namespace for all Curlybars presenters using `config.presenters_namespace`. By default, Curlybars follows standard template name resolution, but setting this option allows you to prepend a custom namespace (e.g., 'Experimental') to presenter lookups, such as `Experimental::Invoices::ShowPresenter`. ```Ruby # config/initializers/curlybars.rb Curlybars.configure do |config| config.presenters_namespace = 'Experimental' end ``` -------------------------------- ### Iterating Over Collections with Curlybars 'each' Helper Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md Shows how to use the 'each' helper to iterate over a collection of objects, such as 'recipient.entries', and access properties of each item within the block. The context changes inside the 'each' block. ```hbs <ul> {{#each recipient.entries}} <li>{{description}} -- ${{amount}}</li> {{/each}} </ul> ``` -------------------------------- ### Invoke Curlybars Helper in Handlebars Template Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md This Handlebars template demonstrates how to invoke the `excerpt` helper with a keyword argument (`max=50`) and display the full `description` from the presenter. It illustrates how to use helpers to transform and present data within a template. ```hbs {{! app/views/invoices/show.html.hbs }} <p>Excerpted description: {{excerpt description max=50}}</p> <p>Full description: {{description}}</p> ``` -------------------------------- ### Configure Curlybars Runtime Limits in Rails (Ruby) Source: https://github.com/zendesk/curlybars/blob/main/README.md This Ruby snippet demonstrates how to configure Curlybars runtime constraints within a Rails initializer. It sets `output_limit` to 2 megabytes and `rendering_timeout` to 5 seconds, providing mechanisms to prevent excessive resource consumption during template rendering. ```ruby Curlybars.configure do |config| config.output_limit = 2.megabytes config.rendering_timeout = 5.seconds end ``` -------------------------------- ### Add Curlybars Gem to Gemfile Source: https://github.com/zendesk/curlybars/blob/main/README.md Instructions to add the Curlybars gem to a Ruby on Rails project's Gemfile for dependency management, allowing for version specification. ```Ruby gem 'curlybars' ``` -------------------------------- ### Configure Curlybars Output Size Limit and Rendering Timeout in Ruby Source: https://github.com/zendesk/curlybars/blob/main/docs/configuration.md This snippet demonstrates how to set the maximum allowed size for the rendered output (`output_limit`) and the maximum rendering time (`rendering_timeout`) for Curlybars. These limits help ensure system stability and control generated response traffic. The configuration is typically placed in a Rails initializer file. ```Ruby # config/initializers/curlybars.rb Curlybars.configure do |config| config.output_limit = 2.megabytes config.rendering_timeout = 5.seconds end ``` -------------------------------- ### Curlybars Helper Invocation and Ruby Signature Matching Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md These snippets illustrate the rules for invoking Curlybars helpers in Handlebars templates and the corresponding Ruby method signatures required to correctly receive arguments and keyword arguments. It covers scenarios where arguments match parameters, extra arguments are discarded, missing parameters receive `nil`, and how to explicitly discard options. ```hbs {{helper 'argument' key1='value1'}} ``` ```ruby def helper(parameter, options) ... end ``` ```hbs {{helper 'argument' 'other' key1='value1'}} ``` ```ruby def helper(parameter, options) # 'argument' is assigned to the first parameter, # and the second parameter is a hash of this form: { key1: 'value1' } end ``` ```hbs {{helper 'argument' key1='value1'}} ``` ```ruby def helper(parameter, second_argument, options) # second_argument will be nil end ``` ```hbs {{helper 'argument' key1='value1'}} ``` ```ruby def helper # will discard anything end ``` ```hbs {{helper 'argument'}} ``` ```ruby def helper(argument, options) # will use the only argument end ``` ```hbs {{helper 'argument'}} ``` ```ruby def helper(argument, _) # will discard options in a more readable way end ``` -------------------------------- ### Defining a Global Helper Class in Curlybars (Ruby) Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md Illustrates how to define a global helper by creating a Plain Old Ruby Object (PORO) class that extends `Curlybars::MethodWhitelist` and defines helper methods like `excerpt`. Global helpers are available throughout the template without specific presenter scope. ```ruby class Helpers::GlobalHelper extend Curlybars::MethodWhitelist allow_methods :excerpt def excerpt(context, options) max = options.fetch(:max, 120) context.to_s.truncate(max) end end ``` -------------------------------- ### Define Invoice Model Class in Ruby Source: https://github.com/zendesk/curlybars/blob/main/README.md Ruby class definition for an Invoice model, demonstrating initialization with amount and recipient, and providing accessor methods for these attributes. ```Ruby # app/models/invoice.rb class Invoice def initialize(amount:, recipient:) @amount = amount @recipient = recipient end def amount @amount end def recipient @recipient end end ``` -------------------------------- ### Defining Generic Presenter Helpers in Curlybars (Ruby) Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md Explains how to define generic presenter helpers in Ruby, which infer their return type from the first argument. This allows for flexible helpers like `translate` that can operate on various presenter types, defined in global helper classes or root/PORO presenters using `Curlybars::Generic`. ```ruby class Helpers::GlobalHelper extend Curlybars::MethodWhitelist allow_methods translate: Curlybars::Generic def translate(presenter, locale, _options) presenter.translate(locale) end end ``` ```rb class CustomPresenter extend Curlybars::MethodWhitelist allow_methods do_something: [:helper, Curlybars::Generic] end ``` -------------------------------- ### Iterating Filtered and Sliced Collections in Curlybars 'each' Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md Demonstrates combining 'each' with subexpressions to first filter a collection ('articles' by 'author.name') and then slice the result before iterating over the filtered and sliced items. ```hbs {{#each (slice (filter articles on="author.name" equals="Libo") 0 4)}} <section> <h3>{{title}}</h3> <div>{{excerpt body}}</div> </section> {{/each}} ``` -------------------------------- ### Using Generic Presenter Helpers in Curlybars Templates Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md Demonstrates how to use generic presenter helpers within Curlybars templates, specifically with the `#with` statement. The `translate` helper is shown translating an `article` object, with its return type inferred as `ArticlePresenter` based on the first argument. ```hbs {{#with (translate article "en-US")}} <section> <h3>{{title}}</h3> <div>{{excerpt body}}</div> </section> {{/each}} ``` -------------------------------- ### Curlybars Template: Conditional Rendering with `if-else` Block Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet illustrates the {{#if ...}}{{else}}{{/if}} block for handling dual conditions in Curlybars templates. It allows rendering one block of content if the condition is true, and an alternative block if the condition is false. ```hbs <h1>Invoice</h1> <p> {{#if has_different_delivery_address}} The delivery address is different from the billing address. {{else}} The delivery and billing addresses are the same. {{/if}} </p> <p>Recipient: {{recipient.name}}</p> ``` -------------------------------- ### Define Recipient Model Class in Ruby Source: https://github.com/zendesk/curlybars/blob/main/README.md Ruby class definition for a Recipient model, demonstrating initialization with a name and providing an accessor method for the name attribute. ```Ruby # app/models/recipient.rb class Recipient def initialize(name:) @name = name end def name @name end end ``` -------------------------------- ### Passing Root Context to a Curlybars Helper with 'this' Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md Demonstrates how to pass the current context, resolved by a 'with' block, to a helper using the 'this' keyword in Curlybars. The 'print_details' helper receives the 'recipient.details' object. ```hbs {{#with recipient.details}} {{print_details this}} {{/with}} ``` -------------------------------- ### Use Generic Collection Helpers in Curlybars Template Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md This Handlebars (Curlybars) template snippet demonstrates the practical application of generic collection helpers like `slice` and `filter`. It shows how to chain these helpers to manipulate a collection, such as filtering articles by author and then slicing the result, before iterating over them to display specific properties. ```hbs {{#each (slice (filter articles on="author.name" equals="Libo") 0 4)}} <section> <h3>{{title}}</h3> <div>{{excerpt body}}</div> </section> {{/each}} ``` -------------------------------- ### Curlybars 'with' Construct with 'else' Block Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet illustrates how to add an 'else' block to the 'with' construct in Curlybars. The 'else' block's content is rendered if the prefix path provided to 'with' is not defined, allowing for fallback content. ```hbs {{#with recipient.details}} <div> <p>Billing address: {{billing_address}}</p> <p>Delivery address: {{delivery_address}}</p> <p>Company name: {{company.name}}</p> </div> {{else}} <p>Details are not available.</p> {{/with}} ``` -------------------------------- ### Define a PORO Presenter for Recipients in Curlybars (Ruby) Source: https://github.com/zendesk/curlybars/blob/main/README.md This Ruby snippet defines `RecipientPresenter`, a Plain Old Ruby Object (PORO) presenter that extends `Curlybars::MethodWhitelist`. It whitelists the `name` method, allowing templates to access the recipient's name. This presenter is designed for nested data structures within a root presenter. ```ruby class RecipientPresenter extend Curlybars::MethodWhitelist allow_methods :name def initialize(recipient) @recipient = recipient end def name @recipient.name end end ``` -------------------------------- ### Curlybars Template: Adding a Comment Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet demonstrates how to add comments to a Curlybars template using the {{! ... }} syntax. Comments are useful for adding notes that do not appear in the rendered output, helping to document the template's purpose. ```hbs {{! This template shows details of an invoice }} <h1>Invoice</h1> <p>Some details on the invoice</p> ``` -------------------------------- ### Invoking a Curlybars Helper with Parameters Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet illustrates how to use a helper in Curlybars templates to add custom functionality, such as truncating text. It shows the 'excerpt' helper being called with a path and a named parameter ('characters'). ```hbs <h1>Invoice</h1> <h2>{{excerpt item.description characters=50}}</h2> ... ``` -------------------------------- ### Curlybars Conditionals with Subexpressions ('if' and 'eval') Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md Illustrates using a subexpression within an 'if' helper to evaluate a condition. The 'eval' helper is used to compare the collection's length to zero, determining which block to render. ```hbs {{#if (eval collection.length "==" 0)}} <div>Empty collection.</div> {{else}} <div>Your collection has {{collection.length}} items</div> {{/if}} ``` -------------------------------- ### Curlybars Template: Conditional Rendering with `if` Block Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet shows how to conditionally render parts of a template using the {{#if ...}} block. The content within the block is rendered only if the provided expression, such as a path or literal, evaluates to a truthy value. ```hbs <h1>Invoice</h1> {{#if has_different_delivery_address}} <p>The delivery address is different from the billing address.</p> {{/if}} <p>Recipient: {{recipient.name}}</p> ``` -------------------------------- ### Define Generic Collection Helper in Global Helper (Ruby) Source: https://github.com/zendesk/curlybars/blob/main/docs/helpers.md This Ruby snippet illustrates how to define a generic collection helper, such as `slice`, within a `Helpers::GlobalHelper` class. It uses `allow_methods` with `Curlybars::Generic` to enable type inference for the helper's return value based on its first argument. ```ruby class Helpers::GlobalHelper extend Curlybars::MethodWhitelist allow_methods slice: [Curlybars::Generic] def slice(collection, start, length, _options) collection.slice(start, length) end end ``` -------------------------------- ### Curlybars Template: Using Literals (String, Boolean, Number) Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet illustrates the use of literal values within Curlybars expressions. Curlybars supports string (single or double quotes), boolean (true, false), and number (integers) literals, which can be used directly as valid expressions. ```hbs A string: {{ 'hello world' }} A boolean: {{ true }} A number: {{ 42 }} ``` -------------------------------- ### Curlybars Lexer Error: Mismatched Quotes or Invalid Path Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This snippet demonstrates a `Curlybars::Error::Lex` exception, which occurs during the lexing phase. It shows two common scenarios: a string surrounded by different types of quotes and a path using commas instead of dots, both leading to a lexing error. ```hbs {{! a string cannot be surrounded by two different types of quotes }} {{t 'a string"}} ``` ```hbs {{! a path cannot be written using commas (only dots are valid) }} {{first,second}} ``` -------------------------------- ### Curlybars Default Whitespace Rendering Source: https://github.com/zendesk/curlybars/blob/main/docs/templates.md This snippet illustrates how Curlybars renders verbatim text, including any surrounding whitespace, when an expression evaluates to true. It shows that spaces around an injected value are preserved in the output HTML. ```hbs <p class="{{#if highlighted}} highlight {{/if}}"> ... </p> ``` ```hbs <p class=" highlight "> ... </p> ``` -------------------------------- ### Curlybars Parser Error: Iterating Over Non-Collection Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This snippet illustrates a `Curlybars::Error::Parse` exception, raised when the `#each` block helper attempts to iterate over a non-collection type, such as a string. The parser expects a collection for iteration. ```hbs {{! #each can only iterate over a collection }} {{#each 'a string'}} {{/each}} ``` -------------------------------- ### Curlybars Compiler Error: Mismatched Block Helper Closing Tag Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This snippet demonstrates a `Curlybars::Error::Compile` exception with the `compile.closing_tag_mismatch` ID. It occurs when a block helper is not closed by a tag with the same name, indicating a structural error during compilation. ```hbs {{! a block helper can only be closed by a tag with the same name }} {{#foo}} {{/bar}} ``` -------------------------------- ### Curlybars Validation Error: Mismatched Block Helper Closing Tag Source: https://github.com/zendesk/curlybars/blob/main/docs/errors.md This snippet shows a `Curlybars::Error::Validate` exception with the `validate.closing_tag_mismatch` ID. This error is raised during the validation phase when a custom block helper is not closed by a tag with the identical name. ```hbs {{! a block helper can only be closed by a tag with the same name }} {{#foo}} ... {{/bar}} ```