module Jekyll::Filters
Constants
- FLOAT_LIKE
- INTEGER_LIKE
Public Instance Methods
Join an array of things into a string by separating with commas and the word “and” for the last one.
array - The Array of Strings to join. connector - Word used to connect the last 2 items in the array
Examples
array_to_sentence_string(["apples", "oranges", "grapes"]) # => "apples, oranges, and grapes"
Returns the formatted String.
# File lib/jekyll/filters.rb, line 152 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
CGI escape a string for use in a URL
. Replaces any special characters with appropriate %XX replacements.
input - The String to escape.
Examples
cgi_escape('foo,bar;baz?') # => "foo%2Cbar%3Bbaz%3F"
Returns the escaped String.
# File lib/jekyll/filters.rb, line 92 def cgi_escape(input) CGI.escape(input) end
Search an array of objects and returns the first object that has the queried attribute with the given value or returns nil otherwise.
input - the object array. property - the property within each object to search by. value - the desired value.
Cannot be an instance of Array nor Hash since calling #to_s on them returns their `#inspect` string object.
Returns the found object or nil
rubocop:disable Metrics/CyclomaticComplexity
# File lib/jekyll/filters.rb, line 235 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
Searches an array of objects against an expression and returns the first object for which the expression evaluates to true, or returns nil otherwise.
input - the object array variable - the variable to assign each item to in the expression expression - a Liquid comparison expression passed in as a string
Returns the found object or nil
# File lib/jekyll/filters.rb, line 268 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
Convert an object into its String representation for debugging
input - The Object
to be converted
Returns a String representation of the object.
# File lib/jekyll/filters.rb, line 371 def inspect(input) xml_escape(input.inspect) end
Convert the input into json string
input - The Array or Hash to be converted
Returns the converted json string
# File lib/jekyll/filters.rb, line 170 def jsonify(input) as_liquid(input).to_json end
Convert a Markdown string into HTML output.
input - The Markdown String to convert.
Returns the HTML formatted String.
# File lib/jekyll/filters.rb, line 16 def markdownify(input) @context.registers[:site].find_converter_instance( Jekyll::Converters::Markdown ).convert(input.to_s) end
Replace any whitespace in the input string with a single space
input - The String on which to operate.
Returns the formatted String
# File lib/jekyll/filters.rb, line 115 def normalize_whitespace(input) input.to_s.gsub(%r!\s+!, " ").tap(&:strip!) end
Count the number of words in the input string.
input - The String on which to operate.
Returns the Integer word count.
# File lib/jekyll/filters.rb, line 124 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
# File lib/jekyll/filters.rb, line 321 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
# File lib/jekyll/filters.rb, line 330 def push(array, input) return array unless array.is_a?(Array) new_ary = array.dup new_ary.push(input) new_ary end
# File lib/jekyll/filters.rb, line 355 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
Convert a Sass string into CSS output.
input - The Sass String to convert.
Returns the CSS formatted String.
# File lib/jekyll/filters.rb, line 38 def sassify(input) @context.registers[:site].find_converter_instance( Jekyll::Converters::Sass ).convert(input) end
Convert a Scss string into CSS output.
input - The Scss String to convert.
Returns the CSS formatted String.
# File lib/jekyll/filters.rb, line 49 def scssify(input) @context.registers[:site].find_converter_instance( Jekyll::Converters::Scss ).convert(input) end
# File lib/jekyll/filters.rb, line 338 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
Slugify a filename or title.
input - The filename or title to slugify. mode - how string is slugified
Returns the given filename or title as a lowercase URL
String. See Utils.slugify
for more detail.
# File lib/jekyll/filters.rb, line 62 def slugify(input, mode = nil) Utils.slugify(input, :mode => mode) end
Convert quotes into smart quotes.
input - The String to convert.
Returns the smart-quotified String.
# File lib/jekyll/filters.rb, line 27 def smartify(input) @context.registers[:site].find_converter_instance( Jekyll::Converters::SmartyPants ).convert(input.to_s) end
Sort an array of objects
input - the object array property - property within each object to filter by nils (‘first’ | ‘last’) - nils appear before or after non-nil values
Returns the filtered array of objects
# File lib/jekyll/filters.rb, line 301 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
Convert the input into integer
input - the object string
Returns the integer value
# File lib/jekyll/filters.rb, line 287 def to_integer(input) return 1 if input == true return 0 if input == false input.to_i end
# File lib/jekyll/filters.rb, line 347 def unshift(array, input) return array unless array.is_a?(Array) new_ary = array.dup new_ary.unshift(input) new_ary end
URI escape a string.
input - The String to escape.
Examples
uri_escape('foo, bar \\baz?') # => "foo,%20bar%20%5Cbaz?"
Returns the escaped String.
# File lib/jekyll/filters.rb, line 106 def uri_escape(input) Addressable::URI.normalize_component(input) end
Filter an array of objects
input - the object array. property - the property within each object to filter by. value - the desired value.
Cannot be an instance of Array nor Hash since calling #to_s on them returns their `#inspect` string object.
Returns the filtered array of objects
# File lib/jekyll/filters.rb, line 183 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
Filters
an array of objects against an expression
input - the object array variable - the variable to assign each item to in the expression expression - a Liquid comparison expression passed in as a string
Returns the filtered array of objects
# File lib/jekyll/filters.rb, line 209 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
XML escape a string for use. Replaces any special characters with appropriate HTML entity replacements.
input - The String to escape.
Examples
xml_escape('foo "bar" <baz>') # => "foo "bar" <baz>"
Returns the escaped String.
# File lib/jekyll/filters.rb, line 77 def xml_escape(input) input.to_s.encode(:xml => :attr).gsub(%r!\A"|"\Z!, "") end
Private Instance Methods
# File lib/jekyll/filters.rb, line 459 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
‘where` filter helper
# File lib/jekyll/filters.rb, line 400 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
# File lib/jekyll/filters.rb, line 421 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
Generate a Liquid::Condition object from a Liquid::Parser object additionally processing the parsed expression based on whether the expression consists of binary operations with Liquid operators ‘and` or `or`
- parser: an instance of Liquid::Parser
Returns an instance of Liquid::Condition
# File lib/jekyll/filters.rb, line 499 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
Generates a Liquid::Condition object from a Liquid::Parser object based on whether the parsed expression involves a “comparison” operator (e.g. <, ==, >, !=, etc)
- parser: an instance of Liquid::Parser
Returns an instance of Liquid::Condition
# File lib/jekyll/filters.rb, line 516 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
Parse a string to a Liquid Condition
# File lib/jekyll/filters.rb, line 484 def parse_condition(exp) parser = Liquid::Parser.new(exp) condition = parse_binary_comparison(parser) parser.consume(:end_of_string) condition end
return numeric values as numbers for proper sorting
# File lib/jekyll/filters.rb, line 451 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
# File lib/jekyll/filters.rb, line 438 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
Sort the input Enumerable by the given property. If the property doesn’t exist, return the sort order respective of which item doesn’t have the property. We also utilize the Schwartzian transform to make this more efficient.
# File lib/jekyll/filters.rb, line 381 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