module Jekyll::Filters
def array_to_sentence_string(array, connector = "and")
# => "apples, oranges, and grapes"
array_to_sentence_string(["apples", "oranges", "grapes"])
Examples
connector - Word used to connect the last 2 items in the array
array - The Array of Strings to join.
word "and" for the last one.
Join an array of things into a string by separating with commas and the
def array_to_sentence_string(array, connector = "and") case array.length when 0 "" when 1 array[0].to_s when 2 "#{array[0]} #{connector} #{array[1]}" else "#{array[0...-1].join(", ")}, #{connector} #{array[-1]}" end end
def as_liquid(item)
def as_liquid(item) case item when Hash item.each_with_object({}) { |(k, v), result| result[as_liquid(k)] = as_liquid(v) } when Array item.map { |i| as_liquid(i) } else if item.respond_to?(:to_liquid) liquidated = item.to_liquid # prevent infinite recursion for simple types (which return `self`) if liquidated == item item else as_liquid(liquidated) end else item end end end
def cgi_escape(input)
# => "foo%2Cbar%3Bbaz%3F"
cgi_escape('foo,bar;baz?')
Examples
input - The String to escape.
with appropriate %XX replacements.
CGI escape a string for use in a URL. Replaces any special characters
def cgi_escape(input) CGI.escape(input) end
def compare_property_vs_target(property, target)
`where` filter helper
def compare_property_vs_target(property, target) case target when NilClass return true if property.nil? when Liquid::Expression::MethodLiteral # `empty` or `blank` target = target.to_s return true if property == target || Array(property).join == target else target = target.to_s if property.is_a? String return true if property == target else Array(property).each do |prop| return true if prop.to_s == target end end end false end
def find(input, property, value)
Returns the found object or nil
their `#inspect` string object.
Cannot be an instance of Array nor Hash since calling #to_s on them returns
value - the desired value.
property - the property within each object to search by.
input - the object array.
with the given value or returns nil otherwise.
Search an array of objects and returns the first object that has the queried attribute
def find(input, property, value) return input if !property || value.is_a?(Array) || value.is_a?(Hash) return input unless input.respond_to?(:find) input = input.values if input.is_a?(Hash) input_id = input.hash # implement a hash based on method parameters to cache the end-result for given parameters. @find_filter_cache ||= {} @find_filter_cache[input_id] ||= {} @find_filter_cache[input_id][property] ||= {} # stash or retrieve results to return # Since `enum.find` can return nil or false, we use a placeholder string "<__NO MATCH__>" # to validate caching. result = @find_filter_cache[input_id][property][value] ||= input.find do |object| compare_property_vs_target(item_property(object, property), value) end || "<__NO MATCH__>" return nil if result == "<__NO MATCH__>" result end
def find_exp(input, variable, expression)
expression - a Liquid comparison expression passed in as a string
variable - the variable to assign each item to in the expression
input - the object array
the expression evaluates to true, or returns nil otherwise.
Searches an array of objects against an expression and returns the first object for which
def find_exp(input, variable, expression) return input unless input.respond_to?(:find) input = input.values if input.is_a?(Hash) condition = parse_condition(expression) @context.stack do input.find do |object| @context[variable] = object condition.evaluate(@context) end end end
def inspect(input)
input - The Object to be converted
Convert an object into its String representation for debugging
def inspect(input) xml_escape(input.inspect) end
def item_property(item, property)
def item_property(item, property) @item_property_cache ||= @context.registers[:site].filter_cache[:item_property] ||= {} @item_property_cache[property] ||= {} @item_property_cache[property][item] ||= begin property = property.to_s property = if item.respond_to?(:to_liquid) read_liquid_attribute(item.to_liquid, property) elsif item.respond_to?(:data) item.data[property] else item[property] end parse_sort_input(property) end end
def jsonify(input)
input - The Array or Hash to be converted
Convert the input into json string
def jsonify(input) as_liquid(input).to_json end
def markdownify(input)
input - The Markdown String to convert.
Convert a Markdown string into HTML output.
def markdownify(input) @context.registers[:site].find_converter_instance( Jekyll::Converters::Markdown ).convert(input.to_s) end
def normalize_whitespace(input)
input - The String on which to operate.
Replace any whitespace in the input string with a single space
def normalize_whitespace(input) input.to_s.gsub(%r!\s+!, " ").tap(&:strip!) end
def number_of_words(input, mode = nil)
input - The String on which to operate.
Count the number of words in the input string.
def number_of_words(input, mode = nil) cjk_charset = '\p{Han}\p{Katakana}\p{Hiragana}\p{Hangul}' cjk_regex = %r![#{cjk_charset}]!o word_regex = %r![^#{cjk_charset}\s]+!o case mode when "cjk" input.scan(cjk_regex).length + input.scan(word_regex).length when "auto" cjk_count = input.scan(cjk_regex).length cjk_count.zero? ? input.split.length : cjk_count + input.scan(word_regex).length else input.split.length end end
def parse_binary_comparison(parser)
- parser: an instance of Liquid::Parser
Liquid operators `and` or `or`
the parsed expression based on whether the expression consists of binary operations with
Generate a Liquid::Condition object from a Liquid::Parser object additionally processing
def parse_binary_comparison(parser) condition = parse_comparison(parser) first_condition = condition while (binary_operator = parser.id?("and") || parser.id?("or")) child_condition = parse_comparison(parser) condition.send(binary_operator, child_condition) condition = child_condition end first_condition end
def parse_comparison(parser)
- parser: an instance of Liquid::Parser
expression involves a "comparison" operator (e.g. <, ==, >, !=, etc)
Generates a Liquid::Condition object from a Liquid::Parser object based on whether the parsed
def parse_comparison(parser) left_operand = Liquid::Expression.parse(parser.expression) operator = parser.consume?(:comparison) # No comparison-operator detected. Initialize a Liquid::Condition using only left operand return Liquid::Condition.new(left_operand) unless operator # Parse what remained after extracting the left operand and the `:comparison` operator # and initialize a Liquid::Condition object using the operands and the comparison-operator Liquid::Condition.new(left_operand, operator, Liquid::Expression.parse(parser.expression)) end
def parse_condition(exp)
def parse_condition(exp) parser = Liquid::Parser.new(exp) condition = parse_binary_comparison(parser) parser.consume(:end_of_string) condition end
def parse_sort_input(property)
def parse_sort_input(property) stringified = property.to_s return property.to_i if INTEGER_LIKE.match?(stringified) return property.to_f if FLOAT_LIKE.match?(stringified) property end
def pop(array, num = 1)
def pop(array, num = 1) return array unless array.is_a?(Array) num = Liquid::Utils.to_integer(num) new_ary = array.dup new_ary.pop(num) new_ary end
def push(array, input)
def push(array, input) return array unless array.is_a?(Array) new_ary = array.dup new_ary.push(input) new_ary end
def read_liquid_attribute(liquid_data, property)
def read_liquid_attribute(liquid_data, property) return liquid_data[property] unless property.include?(".") property.split(".").reduce(liquid_data) do |data, key| data.respond_to?(:[]) && data[key] end end
def sample(input, num = 1)
def sample(input, num = 1) return input unless input.respond_to?(:sample) num = Liquid::Utils.to_integer(num) rescue 1 if num == 1 input.sample else input.sample(num) end end
def sassify(input)
input - The Sass String to convert.
Convert a Sass string into CSS output.
def sassify(input) @context.registers[:site].find_converter_instance( Jekyll::Converters::Sass ).convert(input) end
def scssify(input)
input - The Scss String to convert.
Convert a Scss string into CSS output.
def scssify(input) @context.registers[:site].find_converter_instance( Jekyll::Converters::Scss ).convert(input) end
def shift(array, num = 1)
def shift(array, num = 1) return array unless array.is_a?(Array) num = Liquid::Utils.to_integer(num) new_ary = array.dup new_ary.shift(num) new_ary end
def slugify(input, mode = nil)
Returns the given filename or title as a lowercase URL String.
mode - how string is slugified
input - The filename or title to slugify.
Slugify a filename or title.
def slugify(input, mode = nil) Utils.slugify(input, :mode => mode) end
def smartify(input)
input - The String to convert.
Convert quotes into smart quotes.
def smartify(input) @context.registers[:site].find_converter_instance( Jekyll::Converters::SmartyPants ).convert(input.to_s) end
def sort(input, property = nil, nils = "first")
nils ('first' | 'last') - nils appear before or after non-nil values
property - property within each object to filter by
input - the object array
Sort an array of objects
def sort(input, property = nil, nils = "first") raise ArgumentError, "Cannot sort a null object." if input.nil? if property.nil? input.sort else case nils when "first" order = - 1 when "last" order = + 1 else raise ArgumentError, "Invalid nils order: " \ "'#{nils}' is not a valid nils order. It must be 'first' or 'last'." end sort_input(input, property, order) end end
def sort_input(input, property, order)
which item doesn't have the property.
If the property doesn't exist, return the sort order respective of
Sort the input Enumerable by the given property.
def sort_input(input, property, order) input.map { |item| [item_property(item, property), item] } .sort! do |a_info, b_info| a_property = a_info.first b_property = b_info.first if !a_property.nil? && b_property.nil? - order elsif a_property.nil? && !b_property.nil? + order else a_property <=> b_property || a_property.to_s <=> b_property.to_s end end .map!(&:last) end
def to_integer(input)
input - the object string
Convert the input into integer
def to_integer(input) return 1 if input == true return 0 if input == false input.to_i end
def unshift(array, input)
def unshift(array, input) return array unless array.is_a?(Array) new_ary = array.dup new_ary.unshift(input) new_ary end
def uri_escape(input)
# => "foo,%20bar%20%5Cbaz?"
uri_escape('foo, bar \\baz?')
Examples
input - The String to escape.
URI escape a string.
def uri_escape(input) Addressable::URI.normalize_component(input) end
def where(input, property, value)
their `#inspect` string object.
Cannot be an instance of Array nor Hash since calling #to_s on them returns
value - the desired value.
property - the property within each object to filter by.
input - the object array.
Filter an array of objects
def where(input, property, value) return input if !property || value.is_a?(Array) || value.is_a?(Hash) return input unless input.respond_to?(:select) input = input.values if input.is_a?(Hash) input_id = input.hash # implement a hash based on method parameters to cache the end-result # for given parameters. @where_filter_cache ||= {} @where_filter_cache[input_id] ||= {} @where_filter_cache[input_id][property] ||= {} # stash or retrieve results to return @where_filter_cache[input_id][property][value] ||= input.select do |object| compare_property_vs_target(item_property(object, property), value) end.to_a end
def where_exp(input, variable, expression)
expression - a Liquid comparison expression passed in as a string
variable - the variable to assign each item to in the expression
input - the object array
Filters an array of objects against an expression
def where_exp(input, variable, expression) return input unless input.respond_to?(:select) input = input.values if input.is_a?(Hash) # FIXME condition = parse_condition(expression) @context.stack do input.select do |object| @context[variable] = object condition.evaluate(@context) end end || [] end
def xml_escape(input)
# => "foo "bar" <baz>"
xml_escape('foo "bar"
Examples
input - The String to escape.
appropriate HTML entity replacements.
XML escape a string for use. Replaces any special characters with
def xml_escape(input) input.to_s.encode(:xml => :attr).gsub(%r!\A"|"\Z!, "") end