diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb index a0d35a79..b94ee1ad 100644 --- a/lib/liquid/block_body.rb +++ b/lib/liquid/block_body.rb @@ -98,6 +98,22 @@ module Liquid end end + # @liquid_public_docs + # @liquid_type tag + # @liquid_category syntax + # @liquid_name liquid + # @liquid_summary + # Allows you to have a block of Liquid without delimeters on each tag. + # @liquid_description + # Because the tags don't have delimeters, each tag needs to be on its own line. + # + # > Tip: + # > Use the [`echo` tag](/api/liquid/tags#echo) to output an expression inside `liquid` tags. + # @liquid_syntax + # {% liquid + # expression + # %} + # @liquid_syntax_keyword expression The expression to be rendered inside the `liquid` tag. private def parse_liquid_tag(markup, parse_context) liquid_tag_tokenizer = parse_context.new_tokenizer( markup, start_line_number: parse_context.line_number, for_liquid_tag: true diff --git a/lib/liquid/forloop_drop.rb b/lib/liquid/forloop_drop.rb index 3e1fa020..d0d67ff4 100644 --- a/lib/liquid/forloop_drop.rb +++ b/lib/liquid/forloop_drop.rb @@ -1,6 +1,11 @@ # frozen_string_literal: true module Liquid + # @liquid_public_docs + # @liquid_type object + # @liquid_name forloop + # @liquid_summary + # The `forloop` object contains information about a parent [`for` loop](/api/liquid/tags#for). class ForloopDrop < Drop def initialize(name, length, parentloop) @name = name @@ -9,33 +14,64 @@ module Liquid @index = 0 end - attr_reader :length, :parentloop + # @liquid_public_docs + # @liquid_name forloop.length + # @liquid_summary + # The number of iterations. + # @liquid_return [number] + attr_reader :length + + attr_reader :parentloop def name Usage.increment('forloop_drop_name') @name end + # @liquid_public_docs + # @liquid_summary + # The 1-based index of the current iteration. + # @liquid_return [number] def index @index + 1 end + # @liquid_public_docs + # @liquid_summary + # The 0-based index of the current iteration. + # @liquid_return [number] def index0 @index end + # @liquid_public_docs + # @liquid_summary + # The 1-based index of the current iteration, in reverse order. + # @liquid_return [number] def rindex @length - @index end + # @liquid_public_docs + # @liquid_summary + # The 0-based index of the current iteration, in reverse order. + # @liquid_return [number] def rindex0 @length - @index - 1 end + # @liquid_public_docs + # @liquid_summary + # Returns `true` if the current iteration is the first. Returns `false` if not. + # @liquid_return [boolean] def first @index == 0 end + # @liquid_public_docs + # @liquid_summary + # Returns `true` if the current iteration is the last. Returns `false` if not. + # @liquid_return [boolean] def last @index == @length - 1 end diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index fade736c..3312aafc 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -22,39 +22,107 @@ module Liquid ) STRIP_HTML_TAGS = /<.*?>/m - # Return the size of an array or of an string + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name size + # @liquid_summary + # Returns the size of a string or array. + # @liquid_description + # The size of a string is the number of characters that the string includes. The size of an array is the number of items + # in the array. + # @liquid_syntax variable | size + # @liquid_return [number] def size(input) input.respond_to?(:size) ? input.size : 0 end - # convert an input string to DOWNCASE + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name downcase + # @liquid_summary + # Converts a string to all lowercase characters. + # @liquid_syntax string | downcase + # @liquid_return [string] def downcase(input) input.to_s.downcase end - # convert an input string to UPCASE + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name upcase + # @liquid_summary + # Converts a string to all uppercase characters. + # @liquid_syntax string | upcase + # @liquid_return [string] def upcase(input) input.to_s.upcase end - # capitalize words in the input centence + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name capitalize + # @liquid_summary + # Capitalizes the first word in a string. + # @liquid_syntax string | capitalize + # @liquid_return [string] def capitalize(input) input.to_s.capitalize end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name escape + # @liquid_summary + # Escapes a string. + # @liquid_syntax string | escape + # @liquid_return [string] def escape(input) CGI.escapeHTML(input.to_s) unless input.nil? end alias_method :h, :escape + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name escape_once + # @liquid_summary + # Escapes a string without changing characters that have already been escaped. + # @liquid_syntax string | escape_once + # @liquid_return [string] def escape_once(input) input.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE) end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name url_encode + # @liquid_summary + # Converts any URL-unsafe characters in a string to the + # [percent-encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding) equivalent. + # @liquid_description + # > Note: + # > Spaces are converted to a `+` charcter, instead of a percent-encoded character. + # @liquid_syntax string | url_encode + # @liquid_return [string] def url_encode(input) CGI.escape(input.to_s) unless input.nil? end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name url_decode + # @liquid_summary + # Decodes any [percent-encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding) characters + # in a string. + # @liquid_syntax string | url_decode + # @liquid_return [string] def url_decode(input) return if input.nil? @@ -64,26 +132,71 @@ module Liquid result end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name base64_encode + # @liquid_summary + # Encodes a string to [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64). + # @liquid_syntax string | base64_encode + # @liquid_return [string] def base64_encode(input) Base64.strict_encode64(input.to_s) end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name base64_decode + # @liquid_summary + # Decodes a string in [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64). + # @liquid_syntax string | base64_decode + # @liquid_return [string] def base64_decode(input) Base64.strict_decode64(input.to_s) rescue ::ArgumentError raise Liquid::ArgumentError, "invalid base64 provided to base64_decode" end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name base64_url_safe_encode + # @liquid_summary + # Encodes a string to URL-safe [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64). + # @liquid_syntax string | base64_url_safe_encode + # @liquid_return [string] def base64_url_safe_encode(input) Base64.urlsafe_encode64(input.to_s) end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name base64_url_safe_decode + # @liquid_summary + # Decodes a string in URL-safe [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64). + # @liquid_syntax string | base64_url_safe_decode + # @liquid_return [string] def base64_url_safe_decode(input) Base64.urlsafe_decode64(input.to_s) rescue ::ArgumentError raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode" end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name slice + # @liquid_summary + # Returns a substring or series of array items, starting at a given 0-based index. + # @liquid_description + # By default, the substring has a length of one character, and the array series has one array item. However, you can + # provide a second parameter to specify the number of characters or array items. + # + # You can also supply a negative index which will count from the end of the string. + # @liquid_syntax string | slice + # @liquid_return [string] def slice(input, offset, length = nil) offset = Utils.to_integer(offset) length = length ? Utils.to_integer(length) : 1 @@ -95,7 +208,17 @@ module Liquid end end - # Truncate a string down to x characters + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name truncate + # @liquid_summary + # Truncates a string down to a given number of characters. + # @liquid_description + # If the specified number of characters is less than the length of the string, then an ellipsis (`...`) is appended to + # the truncated string. The ellipsis is included in the character count of the truncated string. + # @liquid_syntax string | truncate: number + # @liquid_return [string] def truncate(input, length = 50, truncate_string = "...") return if input.nil? input_str = input.to_s @@ -109,6 +232,17 @@ module Liquid input_str.length > length ? input_str[0...l].concat(truncate_string_str) : input_str end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name truncatewords + # @liquid_summary + # Truncates a string down to a given number of words. + # @liquid_description + # If the specified number of words is less than the number of words in the string, then an ellipsis (`...`) is appended to + # the truncated string. + # @liquid_syntax string | truncatewords: number + # @liquid_return [string] def truncatewords(input, words = 15, truncate_string = "...") return if input.nil? input = input.to_s @@ -128,27 +262,62 @@ module Liquid wordlist.join(" ").concat(truncate_string.to_s) end - # Split input string into an array of substrings separated by given pattern. - # - # Example: - #
{{ post | split '//' | first }}
- # + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name split + # @liquid_summary + # Splits a string into an array of substrings based on a given separator. + # @liquid_syntax string | split: string + # @liquid_return [array[string]] def split(input, pattern) input.to_s.split(pattern.to_s) end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name strip + # @liquid_summary + # Strips all whitespace from the left and right of a string. + # @liquid_syntax string | strip + # @liquid_return [string] def strip(input) input.to_s.strip end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name lstrip + # @liquid_summary + # Strips all whitespace from the left of a string. + # @liquid_syntax string | lstrip + # @liquid_return [string] def lstrip(input) input.to_s.lstrip end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name rstrip + # @liquid_summary + # Strips all whitespace from the right of a string. + # @liquid_syntax string | rstrip + # @liquid_return [string] def rstrip(input) input.to_s.rstrip end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name strip_html + # @liquid_summary + # Strips all HTML tags from a string. + # @liquid_syntax string | strip_html + # @liquid_return [string] def strip_html(input) empty = '' result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty) @@ -156,18 +325,38 @@ module Liquid result end - # Remove all newlines from the string + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name strip_newlines + # @liquid_summary + # Strips all newline characters (line breaks) from a string. + # @liquid_syntax string | strip_newlines + # @liquid_return [string] def strip_newlines(input) input.to_s.gsub(/\r?\n/, '') end - # Join elements of the array with certain character between them + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name join + # @liquid_summary + # Combines all the items in an array into a single string, separated by a space. + # @liquid_syntax array | join + # @liquid_return [string] def join(input, glue = ' ') InputIterator.new(input, context).join(glue) end - # Sort elements of the array - # provide optional property with which to sort an array of hashes or drops + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name sort + # @liquid_summary + # Sorts the items in an array in case-sensitive alphabetical, or numerical, order. + # @liquid_syntax array | sort + # @liquid_return [array[untyped]] def sort(input, property = nil) ary = InputIterator.new(input, context) @@ -186,8 +375,14 @@ module Liquid end end - # Sort elements of an array ignoring case if strings - # provide optional property with which to sort an array of hashes or drops + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name sort + # @liquid_summary + # Sorts the items in an array in case-insensitive alphabetical, or numerical, order. + # @liquid_syntax array | sort + # @liquid_return [array[untyped]] def sort_natural(input, property = nil) ary = InputIterator.new(input, context) @@ -206,8 +401,19 @@ module Liquid end end - # Filter the elements of an array to those with a certain property value. - # By default the target is any truthy value. + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name where + # @liquid_summary + # Filters an array to include only items with a specific property value. + # @liquid_description + # You can use the `where` filter in the following ways: + # + # - Filter for items with a specific property value. This requires you to provide both the property name and the associated value. + # - Filter for items that have a `true` value for a boolean property. This requires only the property name. + # @liquid_syntax array | where: string, string + # @liquid_return [array[untyped]] def where(input, property, target_value = nil) ary = InputIterator.new(input, context) @@ -234,8 +440,14 @@ module Liquid end end - # Remove duplicate elements from an array - # provide optional property with which to determine uniqueness + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name uniq + # @liquid_summary + # Removes any duplicate items in an array. + # @liquid_syntax array | uniq + # @liquid_return [array[untyped]] def uniq(input, property = nil) ary = InputIterator.new(input, context) @@ -255,13 +467,27 @@ module Liquid end end - # Reverse the elements of an array + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name reverse + # @liquid_summary + # Reverses the order of the items in an array. + # @liquid_syntax array | reverse + # @liquid_return [array[untyped]] def reverse(input) ary = InputIterator.new(input, context) ary.reverse end - # map/collect on a given property + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name map + # @liquid_summary + # Creates an array of values from a specific property of the items in an array. + # @liquid_syntax array | map: string + # @liquid_return [array[untyped]] def map(input, property) InputIterator.new(input, context).map do |e| e = e.call if e.is_a?(Proc) @@ -277,8 +503,14 @@ module Liquid raise_property_error(property) end - # Remove nils within an array - # provide optional property with which to check for nil + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name map + # @liquid_summary + # Removes any `nil` items from an array. + # @liquid_syntax array | compact + # @liquid_return [array[untyped]] def compact(input, property = nil) ary = InputIterator.new(input, context) @@ -298,17 +530,38 @@ module Liquid end end - # Replace occurrences of a string with another + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name replace + # @liquid_summary + # Replaces any instance of a substring inside a string with a given string. + # @liquid_syntax string | replace: string, string + # @liquid_return [string] def replace(input, string, replacement = '') input.to_s.gsub(string.to_s, replacement.to_s) end - # Replace the first occurrences of a string with another + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name replace_first + # @liquid_summary + # Replaces the first instance of a substring inside a string with a given string. + # @liquid_syntax string | replace_first: string, string + # @liquid_return [string] def replace_first(input, string, replacement = '') input.to_s.sub(string.to_s, replacement.to_s) end - # Replace the last occurrences of a string with another + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name replace_last + # @liquid_summary + # Replaces the last instance of a substring inside a string with a given string. + # @liquid_syntax string | replace_last: string, string + # @liquid_return [string] def replace_last(input, string, replacement) input = input.to_s string = string.to_s @@ -323,26 +576,66 @@ module Liquid output end - # remove a substring + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name replace + # @liquid_summary + # Removes any instance of a substring inside a string. + # @liquid_syntax string | remove: string + # @liquid_return [string] def remove(input, string) replace(input, string, '') end - # remove the first occurrences of a substring + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name remove_first + # @liquid_summary + # Removes the first instance of a substring inside a string. + # @liquid_syntax string | remove_first: string + # @liquid_return [string] def remove_first(input, string) replace_first(input, string, '') end - # remove the last occurences of a substring + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name remove_last + # @liquid_summary + # Removes the last instance of a substring inside a string. + # @liquid_syntax string | remove_last: string + # @liquid_return [string] def remove_last(input, string) replace_last(input, string, '') end - # add one string to another + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name append + # @liquid_summary + # Adds a given string to the end of a string. + # @liquid_syntax string | append: string + # @liquid_return [string] def append(input, string) input.to_s + string.to_s end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name concat + # @liquid_summary + # Concatenates (combines) two arrays. + # @liquid_description + # > Note: + # > The `concat` filter won't filter out duplicates. If you want to remove duplicates, then you need to use the + # > [`uniq` filter](/api/liquid/filters#uniq). + # @liquid_syntax array | concat: array + # @liquid_return [array[untyped]] def concat(input, array) unless array.respond_to?(:to_ary) raise ArgumentError, "concat filter requires an array argument" @@ -350,12 +643,26 @@ module Liquid InputIterator.new(input, context).concat(array) end - # prepend a string to another + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name prepend + # @liquid_summary + # Adds a given string to the beginning of a string. + # @liquid_syntax string | prepend: string + # @liquid_return [string] def prepend(input, string) string.to_s + input.to_s end - # Add
tags in front of all newlines in input string + # @liquid_public_docs + # @liquid_type filter + # @liquid_category string + # @liquid_name newline_to_br + # @liquid_summary + # Converts newlines (`\n`) in a string to HTML line breaks (`
`). + # @liquid_syntax string | newline_to_br + # @liquid_return [string] def newline_to_br(input) input.to_s.gsub(/\r?\n/, "
\n") end @@ -399,58 +706,115 @@ module Liquid date.strftime(format.to_s) end - # Get the first element of the passed in array - # - # Example: - # {{ product.images | first | to_img }} - # + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name first + # @liquid_summary + # Returns the first item in the array. + # @liquid_syntax string | first + # @liquid_return [string] def first(array) array.first if array.respond_to?(:first) end - # Get the last element of the passed in array - # - # Example: - # {{ product.images | last | to_img }} - # + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name last + # @liquid_summary + # Returns the last item in the array. + # @liquid_syntax string | last + # @liquid_return [string] def last(array) array.last if array.respond_to?(:last) end - # absolute value + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name abs + # @liquid_summary + # Returns the absolute value of a number. + # @liquid_syntax number | abs + # @liquid_return [number] def abs(input) result = Utils.to_number(input).abs result.is_a?(BigDecimal) ? result.to_f : result end - # addition + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name plus + # @liquid_summary + # Adds two numbers. + # @liquid_syntax number | plus: number + # @liquid_return [number] def plus(input, operand) apply_operation(input, operand, :+) end - # subtraction + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name minus + # @liquid_summary + # Subtracts a given number from another number. + # @liquid_syntax number | minus: number + # @liquid_return [number] def minus(input, operand) apply_operation(input, operand, :-) end - # multiplication + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name times + # @liquid_summary + # Multiplies two numbers. + # @liquid_syntax number | times: number + # @liquid_return [number] def times(input, operand) apply_operation(input, operand, :*) end - # division + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name minus + # @liquid_summary + # Divides a number by a given number. + # @liquid_syntax number | minus: number + # @liquid_return [number] def divided_by(input, operand) apply_operation(input, operand, :/) rescue ::ZeroDivisionError => e raise Liquid::ZeroDivisionError, e.message end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name modulo + # @liquid_summary + # Returns the remainder of dividing a number by a given number. + # @liquid_syntax number | modulo: number + # @liquid_return [number] def modulo(input, operand) apply_operation(input, operand, :%) rescue ::ZeroDivisionError => e raise Liquid::ZeroDivisionError, e.message end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name round + # @liquid_summary + # Rounds a number to the nearest integer. + # @liquid_syntax number | round + # @liquid_return [number] def round(input, n = 0) result = Utils.to_number(input).round(Utils.to_number(n)) result = result.to_f if result.is_a?(BigDecimal) @@ -460,18 +824,42 @@ module Liquid raise Liquid::FloatDomainError, e.message end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name ceil + # @liquid_summary + # Rounds a number up to the nearest integer. + # @liquid_syntax number | ceil + # @liquid_return [number] def ceil(input) Utils.to_number(input).ceil.to_i rescue ::FloatDomainError => e raise Liquid::FloatDomainError, e.message end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name floor + # @liquid_summary + # Rounds a number down to the nearest integer. + # @liquid_syntax number | floor + # @liquid_return [number] def floor(input) Utils.to_number(input).floor.to_i rescue ::FloatDomainError => e raise Liquid::FloatDomainError, e.message end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name at_least + # @liquid_summary + # Limits a number to a minimum value. + # @liquid_syntax number | at_least + # @liquid_return [number] def at_least(input, n) min_value = Utils.to_number(n) @@ -480,6 +868,14 @@ module Liquid result.is_a?(BigDecimal) ? result.to_f : result end + # @liquid_public_docs + # @liquid_type filter + # @liquid_category math + # @liquid_name at_most + # @liquid_summary + # Limits a number to a maximum value. + # @liquid_syntax number | at_most + # @liquid_return [number] def at_most(input, n) max_value = Utils.to_number(n) @@ -488,16 +884,19 @@ module Liquid result.is_a?(BigDecimal) ? result.to_f : result end - # Set a default value when the input is nil, false or empty - # - # Example: - # {{ product.title | default: "No Title" }} - # - # Use `allow_false` when an input should only be tested against nil or empty and not false. - # - # Example: - # {{ product.title | default: "No Title", allow_false: true }} + # @liquid_public_docs + # @liquid_type filter + # @liquid_category array + # @liquid_name default + # @liquid_summary + # Sets a default value for any variable whose value is one of the following: # + # - [`EmptyDrop`](/api/liquid/basics#emptydrop) + # - [`false`](/api/liquid/basics#truthy-and-falsy) + # - [`nil`](/api/liquid/basics#nil) + # @liquid_syntax variable | default: variable + # @liquid_optional_param allow_false [boolean] Whether to use false values instead of the default. + # @liquid_return [variable] def default(input, default_value = '', options = {}) options = {} unless options.is_a?(Hash) false_check = options['allow_false'] ? input.nil? : !Liquid::Utils.to_liquid_value(input) diff --git a/lib/liquid/tablerowloop_drop.rb b/lib/liquid/tablerowloop_drop.rb index 3284b1b7..491562bc 100644 --- a/lib/liquid/tablerowloop_drop.rb +++ b/lib/liquid/tablerowloop_drop.rb @@ -1,6 +1,11 @@ # frozen_string_literal: true module Liquid + # @liquid_public_docs + # @liquid_type object + # @liquid_name forloop + # @liquid_summary + # The `tablerow` object contains information about a parent [`tablerow` loop](/api/liquid/tags#tablerow). class TablerowloopDrop < Drop def initialize(length, cols) @length = length @@ -10,40 +15,95 @@ module Liquid @index = 0 end - attr_reader :length, :col, :row + # @liquid_public_docs + # @liquid_name tablerow.length + # @liquid_summary + # The number of iterations. + # @liquid_return [number] + attr_reader :length + + # @liquid_public_docs + # @liquid_name tablerow.col + # @liquid_summary + # The 1-based index of the current column. + # @liquid_return [number] + attr_reader :col + + # @liquid_public_docs + # @liquid_name tablerow.row + # @liquid_summary + # The 1-based index of current row. + # @liquid_return [number] + attr_reader :row + # @liquid_public_docs + # @liquid_summary + # The 1-based index of the current iteration. + # @liquid_return [number] def index @index + 1 end + # @liquid_public_docs + # @liquid_summary + # The 0-based index of the current iteration. + # @liquid_return [number] def index0 @index end + # @liquid_public_docs + # @liquid_summary + # The 0-based index of the current column. + # @liquid_return [number] def col0 @col - 1 end + # @liquid_public_docs + # @liquid_summary + # The 1-based index of the current iteration, in reverse order. + # @liquid_return [number] def rindex @length - @index end + # @liquid_public_docs + # @liquid_summary + # The 0-based index of the current iteration, in reverse order. + # @liquid_return [number] def rindex0 @length - @index - 1 end + # @liquid_public_docs + # @liquid_summary + # Returns `true` if the current iteration is the first. Returns `false` if not. + # @liquid_return [boolean] def first @index == 0 end + # @liquid_public_docs + # @liquid_summary + # Returns `true` if the current iteration is the last. Returns `false` if not. + # @liquid_return [boolean] def last @index == @length - 1 end + # @liquid_public_docs + # @liquid_summary + # Returns `true` if the current column is the first in the row. Returns `false` if not. + # @liquid_return [boolean] def col_first @col == 1 end + # @liquid_public_docs + # @liquid_summary + # Returns `true` if the current column is the last in the row. Returns `false` if not. + # @liquid_return [boolean] def col_last @col == @cols end diff --git a/lib/liquid/tags/assign.rb b/lib/liquid/tags/assign.rb index 6d4f7d8d..7c0abd87 100644 --- a/lib/liquid/tags/assign.rb +++ b/lib/liquid/tags/assign.rb @@ -1,14 +1,18 @@ # frozen_string_literal: true module Liquid - # Assign sets a variable in your template. - # - # {% assign foo = 'monkey' %} - # - # You can then use the variable later in the page. - # - # {{ foo }} - # + # @liquid_public_docs + # @liquid_type tag + # @liquid_category variable + # @liquid_name assign + # @liquid_summary + # Creates a new variable. + # @liquid_description + # You can create variables of any [basic type](/api/liquid/basics#types), [object](/api/liquid/objects), or object property. + # @liquid_syntax + # {% assign variable_name = value %} + # @liquid_syntax_keyword variable_name The name of the variable being created. + # @liquid_syntax_keyword value The value you want to assign to the variable. class Assign < Tag Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om diff --git a/lib/liquid/tags/break.rb b/lib/liquid/tags/break.rb index 15b33dda..7e138c8a 100644 --- a/lib/liquid/tags/break.rb +++ b/lib/liquid/tags/break.rb @@ -1,15 +1,14 @@ # frozen_string_literal: true module Liquid - # Break tag to be used to break out of a for loop. - # - # == Basic Usage: - # {% for item in collection %} - # {% if item.condition %} - # {% break %} - # {% endif %} - # {% endfor %} - # + # @liquid_public_docs + # @liquid_type tag + # @liquid_category iteration + # @liquid_name break + # @liquid_summary + # Stops a [`for` loop](/api/liquid/tags#for) from iterating. + # @liquid_syntax + # {% break %} class Break < Tag INTERRUPT = BreakInterrupt.new.freeze diff --git a/lib/liquid/tags/capture.rb b/lib/liquid/tags/capture.rb index 3eb63bba..1b9f2819 100644 --- a/lib/liquid/tags/capture.rb +++ b/lib/liquid/tags/capture.rb @@ -1,17 +1,20 @@ # frozen_string_literal: true module Liquid - # Capture stores the result of a block into a variable without rendering it inplace. - # - # {% capture heading %} - # Monkeys! + # @liquid_public_docs + # @liquid_type tag + # @liquid_category variable + # @liquid_name capture + # @liquid_summary + # Creates a new variable with a string value. + # @liquid_description + # You can create complex strings with Liquid logic and variables. + # @liquid_syntax + # {% capture variable %} + # value # {% endcapture %} - # ... - #

{{ heading }}

- # - # Capture is useful for saving content for use later in your template, such as - # in a sidebar or footer. - # + # @liquid_syntax_keyword variable The name of the variable being created. + # @liquid_syntax_keyword value The value you want to assign to the variable. class Capture < Block Syntax = /(#{VariableSignature}+)/o diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb index d6ab64e6..3dacf0d5 100644 --- a/lib/liquid/tags/case.rb +++ b/lib/liquid/tags/case.rb @@ -1,6 +1,24 @@ # frozen_string_literal: true module Liquid + # @liquid_public_docs + # @liquid_type tag + # @liquid_category conditional + # @liquid_name case + # @liquid_summary + # Renders a specific expression depending on the value of a specific variable. + # @liquid_syntax + # {% case variable %} + # {% when value %} + # expression + # {% when value %} + # expression + # {% else %} + # expression + # {% endcase %} + # @liquid_syntax_keyword variable The name of the variable you want to base your case statement on. + # @liquid_syntax_keyword value A specific value to check for. + # @liquid_syntax_keyword expression An expression to be rendered when the variable's value matches the value being checked. class Case < Block Syntax = /(#{QuotedFragment})/o WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om diff --git a/lib/liquid/tags/comment.rb b/lib/liquid/tags/comment.rb index a5460f99..51cea5c3 100644 --- a/lib/liquid/tags/comment.rb +++ b/lib/liquid/tags/comment.rb @@ -1,6 +1,19 @@ # frozen_string_literal: true module Liquid + # @liquid_public_docs + # @liquid_type tag + # @liquid_category syntax + # @liquid_name comment + # @liquid_summary + # Prevents an expression from being rendered or output. + # @liquid_description + # Any text inside `comment` tags won't be output, and any Liquid code won't be rendered. + # @liquid_syntax + # {% comment %} + # content + # {% endcomment %} + # @liquid_syntax_keyword content The content of the comment. class Comment < Block def render_to_output_buffer(_context, output) output diff --git a/lib/liquid/tags/continue.rb b/lib/liquid/tags/continue.rb index a70442f0..2435899e 100644 --- a/lib/liquid/tags/continue.rb +++ b/lib/liquid/tags/continue.rb @@ -1,15 +1,14 @@ # frozen_string_literal: true module Liquid - # Continue tag to be used to break out of a for loop. - # - # == Basic Usage: - # {% for item in collection %} - # {% if item.condition %} - # {% continue %} - # {% endif %} - # {% endfor %} - # + # @liquid_public_docs + # @liquid_type tag + # @liquid_category iteration + # @liquid_name continue + # @liquid_summary + # Causes a [`for` loop](/api/liquid/tags#for) to skip to the next iteration. + # @liquid_syntax + # {% continue %} class Continue < Tag INTERRUPT = ContinueInterrupt.new.freeze diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb index 96f0d570..e81b04aa 100644 --- a/lib/liquid/tags/cycle.rb +++ b/lib/liquid/tags/cycle.rb @@ -1,18 +1,17 @@ # frozen_string_literal: true module Liquid - # Cycle is usually used within a loop to alternate between values, like colors or DOM classes. - # - # {% for item in items %} - #
{{ item }}
- # {% end %} - # - #
Item one
- #
Item two
- #
Item three
- #
Item four
- #
Item five
- # + # @liquid_public_docs + # @liquid_type tag + # @liquid_category iteration + # @liquid_name cycle + # @liquid_summary + # Loops through a group of strings and outputs them one at a time for each iteration of a [`for` loop](/api/liquid/tags#for). + # @liquid_description + # > Note: + # > The `cycle` tag must be used inside a `for` loop. + # @liquid_syntax + # {% cycle string, string, ... %} class Cycle < Tag SimpleSyntax = /\A#{QuotedFragment}+/o NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om diff --git a/lib/liquid/tags/decrement.rb b/lib/liquid/tags/decrement.rb index d761a0c3..593d7c58 100644 --- a/lib/liquid/tags/decrement.rb +++ b/lib/liquid/tags/decrement.rb @@ -1,24 +1,23 @@ # frozen_string_literal: true module Liquid - # decrement is used in a place where one needs to insert a counter - # into a template, and needs the counter to survive across - # multiple instantiations of the template. - # NOTE: decrement is a pre-decrement, --i, - # while increment is post: i++. - # - # (To achieve the survival, the application must keep the context) - # - # if the variable does not exist, it is created with value 0. - - # Hello: {% decrement variable %} - # - # gives you: - # - # Hello: -1 - # Hello: -2 - # Hello: -3 + # @liquid_public_docs + # @liquid_type tag + # @liquid_category variable + # @liquid_name decrement + # @liquid_summary + # Creates a new variable, with a default value of -1, that's decreased by 1 with each subsequent call. + # @liquid_desription + # Variables that are declared with `decrement` are unique to the file ([layout](/themes/architecture/layouts), [section](/themes/architecture/sections), + # or [template](/themes/architecture/templates)) that they're created in. However, these variables are shared across + # [snippets](/themes/architecture#snippets) inside each of those files. # + # Similarly, variables that are created with `decrement` are are unique to those created with [`assign`](/api/liquid/tags#assign) + # and [`capture`](/api/liquid/tags#capture). However, these variables are shared with variables created with + # [`increment`](/api/liquid/tags#increment). + # @liquid_syntax + # {% decrement variable_name %} + # @liquid_syntax_keyword variable_name The name of the variable being decremented. class Decrement < Tag def initialize(tag_name, markup, options) super diff --git a/lib/liquid/tags/echo.rb b/lib/liquid/tags/echo.rb index 19026a08..ff95d7e3 100644 --- a/lib/liquid/tags/echo.rb +++ b/lib/liquid/tags/echo.rb @@ -1,16 +1,21 @@ # frozen_string_literal: true module Liquid - # Echo outputs an expression - # - # {% echo monkey %} - # {% echo user.name %} - # - # This is identical to variable output syntax, like {{ foo }}, but works - # inside {% liquid %} tags. The full syntax is supported, including filters: - # - # {% echo user | link %} + # @liquid_public_docs + # @liquid_type tag + # @liquid_category syntax + # @liquid_name echo + # @liquid_summary + # Outputs an expression. + # @liquid_desription + # Using the `echo` tag is the same as wrapping an expression in `{{` and `}}`, however you can use it inside + # [`liquid` tags](/api/liquid/tags#liquid). # + # > Note: + # > You can use [filters](/api/liquid/filters) on expressions inside `echo` tags. + # @liquid_syntax + # {% echo expression %} + # @liquid_syntax_keyword expression The expression to be output. class Echo < Tag attr_reader :variable diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb index 328ba02a..d56c4b7d 100644 --- a/lib/liquid/tags/for.rb +++ b/lib/liquid/tags/for.rb @@ -1,50 +1,29 @@ # frozen_string_literal: true module Liquid - # "For" iterates over an array or collection. - # Several useful variables are available to you within the loop. - # - # == Basic usage: - # {% for item in collection %} - # {{ forloop.index }}: {{ item.name }} - # {% endfor %} - # - # == Advanced usage: - # {% for item in collection %} - #
- # Item {{ forloop.index }}: {{ item.name }} - #
- # {% else %} - # There is nothing in the collection. - # {% endfor %} - # - # You can also define a limit and offset much like SQL. Remember - # that offset starts at 0 for the first item. - # - # {% for item in collection limit:5 offset:10 %} - # {{ item.name }} - # {% end %} - # - # To reverse the for loop simply use {% for item in collection reversed %} (note that the flag's spelling is different to the filter `reverse`) - # - # == Available variables: - # - # forloop.name:: 'item-collection' - # forloop.length:: Length of the loop - # forloop.index:: The current item's position in the collection; - # forloop.index starts at 1. - # This is helpful for non-programmers who start believe - # the first item in an array is 1, not 0. - # forloop.index0:: The current item's position in the collection - # where the first item is 0 - # forloop.rindex:: Number of items remaining in the loop - # (length - index) where 1 is the last item. - # forloop.rindex0:: Number of items remaining in the loop - # where 0 is the last item. - # forloop.first:: Returns true if the item is the first item. - # forloop.last:: Returns true if the item is the last item. - # forloop.parentloop:: Provides access to the parent loop, if present. + # @liquid_public_docs + # @liquid_type tag + # @liquid_category iteration + # @liquid_name for + # @liquid_summary + # Renders an expression for every item in an array. + # @liquid_desription + # > Tip: + # > Every `for` loop has an associated [`forloop` object](/api/liquid/objects#forloop) with information about the loop. # + # You can do a maximum of 50 iterations with a `for` loop. If you need to iterate over more than 50 items, then use the + # [`paginate` tag](/api/liquid/tags#paginate) to split the items over multiple pages. + # @liquid_syntax + # {% for variable in array %} + # expression + # {% endfor %} + # @liquid_syntax_keyword variable The current item in the array. + # @liquid_syntax_keyword array The array to iterate over. + # @liquid_syntax_keyword expression The expression to render. + # @liquid_optional_param limit [number] The number of iterations to perform. + # @liquid_optional_param offset [number] The 1-based index to start iterating at. + # @liquid_optional_param range [untyped] A custom numeric range to iterate over. + # @liquid_optional_param reversed [untyped] Iterate in reverse order. class For < Block Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb index f4b57d7d..7ef6a886 100644 --- a/lib/liquid/tags/if.rb +++ b/lib/liquid/tags/if.rb @@ -1,16 +1,18 @@ # frozen_string_literal: true module Liquid - # If is the conditional block - # - # {% if user.admin %} - # Admin user! - # {% else %} - # Not admin user + # @liquid_public_docs + # @liquid_type tag + # @liquid_category conditional + # @liquid_name if + # @liquid_summary + # Renders an expression if a specific condition is `true`. + # @liquid_syntax + # {% if condition %} + # expression # {% endif %} - # - # There are {% if count < 5 %} less {% else %} more {% endif %} items than you need. - # + # @liquid_syntax_keyword condition The condition to evaluate. + # @liquid_syntax_keyword expression The expression to render if the condition is met. class If < Block Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o diff --git a/lib/liquid/tags/include.rb b/lib/liquid/tags/include.rb index 1a315443..14e0f881 100644 --- a/lib/liquid/tags/include.rb +++ b/lib/liquid/tags/include.rb @@ -1,20 +1,23 @@ # frozen_string_literal: true module Liquid - # Include allows templates to relate with other templates - # - # Simply include another template: - # - # {% include 'product' %} - # - # Include a template with a local variable: - # - # {% include 'product' with products[0] %} - # - # Include a template for a collection: - # - # {% include 'product' for products %} + # @liquid_public_docs + # @liquid_type tag + # @liquid_category theme + # @liquid_name include + # @liquid_summary + # Renders a [snippet](/themes/architecture#snippets). + # @liquid_description + # Inside the snippet, you can access and alter variables that are [created](/api/liquid/tags#variable-tags) outside of the + # snippet. + # @liquid_syntax + # {% include 'filename' %} + # @liquid_syntax_keyword filename The name of the snippet to render, without the `.liquid` extension. + # @liquid_deprecated + # Deprecated because the way that variables are handled reduces performance and makes code harder to both read and maintain. # + # > Tip: + # > The `include` tag has been replaced by [`render`](/api/liquid/tags#render). class Include < Tag prepend Tag::Disableable diff --git a/lib/liquid/tags/increment.rb b/lib/liquid/tags/increment.rb index 241b316b..b44c6662 100644 --- a/lib/liquid/tags/increment.rb +++ b/lib/liquid/tags/increment.rb @@ -1,21 +1,23 @@ # frozen_string_literal: true module Liquid - # increment is used in a place where one needs to insert a counter - # into a template, and needs the counter to survive across - # multiple instantiations of the template. - # (To achieve the survival, the application must keep the context) - # - # if the variable does not exist, it is created with value 0. - # - # Hello: {% increment variable %} - # - # gives you: - # - # Hello: 0 - # Hello: 1 - # Hello: 2 + # @liquid_public_docs + # @liquid_type tag + # @liquid_category variable + # @liquid_name increment + # @liquid_summary + # Creates a new variable, with a default value of 0, that's increased by 1 with each subsequent call. + # @liquid_desription + # Variables that are declared with `increment` are unique to the file ([layout](/themes/architecture/layouts), [section](/themes/architecture/sections), + # or [template](/themes/architecture/templates)) that they're created in. However, these variables are shared across + # [snippets](/themes/architecture#snippets) inside each of those files. # + # Similarly, variables that are created with `increment` are are unique to those created with [`assign`](/api/liquid/tags#assign) + # and [`capture`](/api/liquid/tags#capture). However, these variables are shared with variables created with + # [`decrement`](/api/liquid/tags#decrement). + # @liquid_syntax + # {% increment variable_name %} + # @liquid_syntax_keyword variable_name The name of the variable being decremented. class Increment < Tag def initialize(tag_name, markup, options) super diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb index 3a5b9901..6ffb6149 100644 --- a/lib/liquid/tags/raw.rb +++ b/lib/liquid/tags/raw.rb @@ -1,6 +1,17 @@ # frozen_string_literal: true module Liquid + # @liquid_public_docs + # @liquid_type tag + # @liquid_category syntax + # @liquid_name raw + # @liquid_summary + # Outputs any Liquid code as text instead of rendering it. + # @liquid_syntax + # {% raw %} + # expression + # {% endraw %} + # @liquid_syntax_keyword expression The expression to be output without being rendered. class Raw < Block Syntax = /\A\s*\z/ FullTokenPossiblyInvalid = /\A(.*)#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}\z/om diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb index 9b838184..4f3e4e56 100644 --- a/lib/liquid/tags/render.rb +++ b/lib/liquid/tags/render.rb @@ -1,6 +1,30 @@ # frozen_string_literal: true module Liquid + # @liquid_public_docs + # @liquid_type tag + # @liquid_category theme + # @liquid_name include + # @liquid_summary + # Renders a [snippet](/themes/architecture#snippets). + # @liquid_description + # > Tip: + # > The `render` tag is also used to [render app blocks](/themes/architecture/sections/section-schema#render-app-blocks). + # + # Inside the snippet, there's no direct access to variables that are [created](/api/liquid/tags#variable-tags) outside + # of the snippet. If you want to pass in outside variables, then you can [specify variables as parameters](/api/liquid/tags#render-passing-variables-to-snippets). + # + # While there's no direct access to created variables, there's access to global objects, as well as any objects that are + # directly accessible outside the snippet. + # + # Outside the snippet, you can't access variables created inside the snippet. + # + # > Note: + # > When a snippet is rendered using the `render` tag, you can't use the [`include` tag](/api/liquid/tags#include) + # > inside the snippet. + # @liquid_syntax + # {% render 'filename' %} + # @liquid_syntax_keyword filename The name of the snippet to render, without the `.liquid` extension. class Render < Tag FOR = 'for' SYNTAX = /(#{QuotedString}+)(\s+(with|#{FOR})\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o diff --git a/lib/liquid/tags/table_row.rb b/lib/liquid/tags/table_row.rb index eda0bc46..698cebf0 100644 --- a/lib/liquid/tags/table_row.rb +++ b/lib/liquid/tags/table_row.rb @@ -1,6 +1,28 @@ # frozen_string_literal: true module Liquid + # @liquid_public_docs + # @liquid_type tag + # @liquid_category iteration + # @liquid_name tablerow + # @liquid_summary + # Generates HTML table rows for every item in an array. + # @liquid_desription + # The `tablerow` tag must be wrapped in HTML `` and `
` tags. + # + # > Tip: + # > Every `tablerow` loop has an associated [`tablerow` object](/api/liquid/objects#tablerow) with information about the loop. + # @liquid_syntax + # {% tablerow variable in array %} + # expression + # {% endtablerow %} + # @liquid_syntax_keyword variable The current item in the array. + # @liquid_syntax_keyword array The array to iterate over. + # @liquid_syntax_keyword expression The expression to render. + # @liquid_optional_param cols [number] The number of columns that the table should have. + # @liquid_optional_param limit [number] The number of iterations to perform. + # @liquid_optional_param offset [number] The 1-based index to start iterating at. + # @liquid_optional_param range [untyped] A custom numeric range to iterate over. class TableRow < Block Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o diff --git a/lib/liquid/tags/unless.rb b/lib/liquid/tags/unless.rb index db725dbf..722d6c52 100644 --- a/lib/liquid/tags/unless.rb +++ b/lib/liquid/tags/unless.rb @@ -3,10 +3,21 @@ require_relative 'if' module Liquid - # Unless is a conditional just like 'if' but works on the inverse logic. - # - # {% unless x < 0 %} x is greater than zero {% endunless %} - # + # @liquid_public_docs + # @liquid_type tag + # @liquid_category conditional + # @liquid_name unless + # @liquid_summary + # Renders an expression unless a specific condition is `true`. + # @liquid_description + # > Tip: + # > Similar to the [`if` tag](/api/liquid/tags#if), you can use `elsif` to add more conditions to an `unless` tag. + # @liquid_syntax + # {% unless condition %} + # expression + # {% endif %} + # @liquid_syntax_keyword condition The condition to evaluate. + # @liquid_syntax_keyword expression The expression to render unless the condition is met. class Unless < If def render_to_output_buffer(context, output) # First condition is interpreted backwards ( if not )