module Bridgetown::Filters

Constants

FLOAT_LIKE
INTEGER_LIKE

Public Instance Methods

array_to_sentence_string(array, connector = "and") click to toggle source

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/bridgetown-core/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(input) click to toggle source

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/bridgetown-core/filters.rb, line 81
def cgi_escape(input)
  CGI.escape(input.to_s)
end
inspect(input = nil) click to toggle source

Convert an object into its String representation for debugging

@param input [Object] The Object to be converted

@return [String] the representation of the object.

Calls superclass method
# File lib/bridgetown-core/filters.rb, line 313
def inspect(input = nil)
  return super() if input.nil?

  xml_escape(input.inspect)
end
jsonify(input) click to toggle source

Convert the input into json string

input - The Array or Hash to be converted

Returns the converted json string

# File lib/bridgetown-core/filters.rb, line 170
def jsonify(input)
  as_liquid(input).to_json
end
markdownify(input) click to toggle source

Convert a Markdown string into HTML output.

input - The Markdown String to convert.

Returns the HTML formatted String.

# File lib/bridgetown-core/filters.rb, line 17
def markdownify(input)
  @context.registers[:site].find_converter_instance(
    Bridgetown::Converters::Markdown
  ).convert(input.to_s)
end
normalize_whitespace(input) click to toggle source

Replace any whitespace in the input string with a single space

input - The String on which to operate.

Returns the formatted String

# File lib/bridgetown-core/filters.rb, line 119
def normalize_whitespace(input)
  input.to_s.gsub(%r!\s+!, " ").strip
end
number_of_words(input) click to toggle source

Count the number of words in the input string.

input - The String on which to operate.

Returns the Integer word count.

# File lib/bridgetown-core/filters.rb, line 128
def number_of_words(input)
  input.split.length
end
pop(array, num = 1) click to toggle source
# File lib/bridgetown-core/filters.rb, line 263
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
push(array, input) click to toggle source
# File lib/bridgetown-core/filters.rb, line 272
def push(array, input)
  return array unless array.is_a?(Array)

  new_ary = array.dup
  new_ary.push(input)
  new_ary
end
reading_time(input, round_to = 0) click to toggle source

Calculates the average reading time of the supplied content. @param input [String] the String of content to analyze. @return [Float] the number of minutes required to read the content.

# File lib/bridgetown-core/filters.rb, line 135
def reading_time(input, round_to = 0)
  wpm = @context.registers[:site].config[:reading_time_wpm] || 250
  (number_of_words(input).to_f / wpm).ceil(round_to)
end
sample(input, num = 1) click to toggle source
# File lib/bridgetown-core/filters.rb, line 297
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
shift(array, num = 1) click to toggle source
# File lib/bridgetown-core/filters.rb, line 280
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(input, mode = nil) click to toggle source

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/bridgetown-core/filters.rb, line 41
def slugify(input, mode = nil)
  mode = @context.registers[:site].config.slugify_mode if mode.nil?
  Utils.slugify(input, mode: mode)
end
smartify(input) click to toggle source

Convert quotes into smart quotes.

input - The String to convert.

Returns the smart-quotified String.

# File lib/bridgetown-core/filters.rb, line 28
def smartify(input)
  @context.registers[:site].find_converter_instance(
    Bridgetown::Converters::SmartyPants
  ).convert(input.to_s)
end
sort(input, property = nil, nils = "first") click to toggle source

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/bridgetown-core/filters.rb, line 244
def sort(input, property = nil, nils = "first")
  raise ArgumentError, "Cannot sort a null object." if input.nil?

  if property.nil?
    input.sort
  else
    if nils == "first"
      order = - 1
    elsif nils == "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
titleize(input) click to toggle source

Titleize a slug or identifier string.

input - The string to titleize.

Returns a transformed string with spaces and capitalized words. See Utils.titleize_slug for more detail.

# File lib/bridgetown-core/filters.rb, line 52
def titleize(input)
  Utils.titleize_slug(input)
end
to_integer(input) click to toggle source

Convert the input into integer

input - the object string

Returns the integer value

# File lib/bridgetown-core/filters.rb, line 230
def to_integer(input)
  return 1 if input == true
  return 0 if input == false

  input.to_i
end
unshift(array, input) click to toggle source
# File lib/bridgetown-core/filters.rb, line 289
def unshift(array, input)
  return array unless array.is_a?(Array)

  new_ary = array.dup
  new_ary.unshift(input)
  new_ary
end
uri_escape(input) click to toggle source

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/bridgetown-core/filters.rb, line 95
def uri_escape(input)
  Addressable::URI.normalize_component(input)
end
where(input, property, value) click to toggle source

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/bridgetown-core/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 retrive results to return
  @where_filter_cache[input_id][property][value] ||= begin
    input.select do |object|
      compare_property_vs_target(item_property(object, property), value)
    end.to_a
  end
end
where_exp(input, variable, expression) click to toggle source

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/bridgetown-core/filters.rb, line 211
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(input) click to toggle source

XML escape a string for use. Replaces any special characters with appropriate HTML entity replacements.

Examples

xml_escape('foo "bar" <baz>')
# => "foo &quot;bar&quot; &lt;baz&gt;"

@param input [String] The String to escape. @return [String] the escaped String.

# File lib/bridgetown-core/filters.rb, line 66
def xml_escape(input)
  Utils.xml_escape(input)
end

Private Instance Methods

as_liquid(item) click to toggle source
# File lib/bridgetown-core/filters.rb, line 412
def as_liquid(item)
  case item
  when Hash
    pairs = item.map { |k, v| as_liquid([k, v]) }
    Hash[pairs]
  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
compare_property_vs_target(property, target) click to toggle source

`where` filter helper

rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/PerceivedComplexity

# File lib/bridgetown-core/filters.rb, line 351
def compare_property_vs_target(property, target)
  case target
  when NilClass
    return true if property.nil?
  when "" # aka `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
item_property(item, property) click to toggle source

rubocop:enable Metrics/CyclomaticComplexity rubocop:enable Metrics/PerceivedComplexity

# File lib/bridgetown-core/filters.rb, line 374
def item_property(item, property)
  @item_property_cache ||= {}
  @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
parse_sort_input(property) click to toggle source

return numeric values as numbers for proper sorting

# File lib/bridgetown-core/filters.rb, line 404
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
read_liquid_attribute(liquid_data, property) click to toggle source
# File lib/bridgetown-core/filters.rb, line 391
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
rot47(input) click to toggle source

Perform a rot47 rotation for obfuscation

# File lib/bridgetown-core/filters.rb, line 322
def rot47(input)
  input.tr "!-~", "P-~!-O"
end
sort_input(input, property, order) click to toggle source

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/bridgetown-core/filters.rb, line 330
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