class Jekyll::Collection

Attributes

docs[W]
label[R]
metadata[R]
site[R]

Public Class Methods

new(site, label) click to toggle source

Create a new Collection.

site - the site to which this collection belongs. label - the name of the collection

Returns nothing.

# File lib/jekyll/collection.rb, line 14
def initialize(site, label)
  @site     = site
  @label    = sanitize_label(label)
  @metadata = extract_metadata
end

Public Instance Methods

collection_dir(*files) click to toggle source

The full path to the directory containing the collection, with

optional subpaths.

*files - (optional) any other path pieces relative to the

directory to append to the path

Returns a String containing th directory name where the collection

is stored on the filesystem.
# File lib/jekyll/collection.rb, line 131
def collection_dir(*files)
  return directory if files.empty?

  site.in_source_dir(container, relative_directory, *files)
end
directory() click to toggle source

The full path to the directory containing the collection.

Returns a String containing th directory name where the collection

is stored on the filesystem.
# File lib/jekyll/collection.rb, line 117
def directory
  @directory ||= site.in_source_dir(
    File.join(container, relative_directory)
  )
end
docs() click to toggle source

Fetch the Documents in this collection. Defaults to an empty array if no documents have been read in.

Returns an array of Jekyll::Document objects.

# File lib/jekyll/collection.rb, line 24
def docs
  @docs ||= []
end
entries() click to toggle source

All the entries in this collection.

Returns an Array of file paths to the documents in this collection

relative to the collection's directory
# File lib/jekyll/collection.rb, line 76
def entries
  return [] unless exists?

  @entries ||= begin
    collection_dir_slash = "#{collection_dir}/"
    Utils.safe_glob(collection_dir, ["**", "*"], File::FNM_DOTMATCH).map do |entry|
      entry[collection_dir_slash] = ""
      entry
    end
  end
end
entry_filter() click to toggle source

The entry filter for this collection. Creates an instance of Jekyll::EntryFilter.

Returns the instance of Jekyll::EntryFilter for this collection.

# File lib/jekyll/collection.rb, line 151
def entry_filter
  @entry_filter ||= Jekyll::EntryFilter.new(site, relative_directory)
end
exists?() click to toggle source

Checks whether the directory “exists” for this collection. The directory must exist on the filesystem and must not be a symlink

if in safe mode.

Returns false if the directory doesn’t exist or if it’s a symlink

and we're in safe mode.
# File lib/jekyll/collection.rb, line 143
def exists?
  File.directory?(directory) && !entry_filter.symlink?(directory)
end
extract_metadata() click to toggle source

Extract options for this collection from the site configuration.

Returns the metadata for this collection

# File lib/jekyll/collection.rb, line 203
def extract_metadata
  if site.config["collections"].is_a?(Hash)
    site.config["collections"][label] || {}
  else
    {}
  end
end
files() click to toggle source

Fetch the static files in this collection. Defaults to an empty array if no static files have been read in.

Returns an array of Jekyll::StaticFile objects.

# File lib/jekyll/collection.rb, line 50
def files
  @files ||= []
end
filtered_entries() click to toggle source

Filtered version of the entries in this collection. See ‘Jekyll::EntryFilter#filter` for more information.

Returns a list of filtered entry paths.

# File lib/jekyll/collection.rb, line 92
def filtered_entries
  return [] unless exists?

  @filtered_entries ||=
    Dir.chdir(directory) do
      entry_filter.filter(entries).reject do |f|
        path = collection_dir(f)
        File.directory?(path) || entry_filter.symlink?(f)
      end
    end
end
inspect() click to toggle source

An inspect string.

Returns the inspect string

# File lib/jekyll/collection.rb, line 158
def inspect
  "#<#{self.class} @label=#{label} docs=#{docs}>"
end
method_missing(method, *args, &blck) click to toggle source

Override of method_missing to check in @data for the key.

Calls superclass method
# File lib/jekyll/collection.rb, line 35
def method_missing(method, *args, &blck)
  if docs.respond_to?(method.to_sym)
    Jekyll.logger.warn "Deprecation:",
                       "#{label}.#{method} should be changed to #{label}.docs.#{method}."
    Jekyll.logger.warn "", "Called by #{caller(0..0)}."
    docs.public_send(method.to_sym, *args, &blck)
  else
    super
  end
end
read() click to toggle source

Read the allowed documents into the collection’s array of docs.

Returns the sorted array of docs.

# File lib/jekyll/collection.rb, line 57
def read
  filtered_entries.each do |file_path|
    full_path = collection_dir(file_path)
    next if File.directory?(full_path)

    if Utils.has_yaml_header? full_path
      read_document(full_path)
    else
      read_static_file(file_path, full_path)
    end
  end
  site.static_files.concat(files) unless files.empty?
  sort_docs!
end
relative_directory() click to toggle source

The directory for this Collection, relative to the site source or the directory containing the collection.

Returns a String containing the directory name where the collection

is stored on the filesystem.
# File lib/jekyll/collection.rb, line 109
def relative_directory
  @relative_directory ||= "_#{label}"
end
respond_to_missing?(method, include_private = false) click to toggle source

Override of normal respond_to? to match method_missing‘s logic for looking in @data.

Calls superclass method
# File lib/jekyll/collection.rb, line 30
def respond_to_missing?(method, include_private = false)
  docs.respond_to?(method.to_sym, include_private) || super
end
sanitize_label(label) click to toggle source

Produce a sanitized label name Label names may not contain anything but alphanumeric characters,

underscores, and hyphens.

label - the possibly-unsafe label

Returns a sanitized version of the label.

# File lib/jekyll/collection.rb, line 169
def sanitize_label(label)
  label.gsub(%r![^a-z0-9_\-.]!i, "")
end
to_liquid() click to toggle source

Produce a representation of this Collection for use in Liquid. Exposes two attributes:

- label
- docs

Returns a representation of this collection for use in Liquid.

# File lib/jekyll/collection.rb, line 179
def to_liquid
  Drops::CollectionDrop.new self
end
url_template() click to toggle source

The URL template to render collection’s documents at.

Returns the URL template to render collection’s documents at.

# File lib/jekyll/collection.rb, line 194
def url_template
  @url_template ||= metadata.fetch("permalink") do
    Utils.add_permalink_suffix("/:collection/:path", site.permalink_style)
  end
end
write?() click to toggle source

Whether the collection’s documents ought to be written as individual

files in the output.

Returns true if the ‘write’ metadata is true, false otherwise.

# File lib/jekyll/collection.rb, line 187
def write?
  !!metadata.fetch("output", false)
end

Private Instance Methods

container() click to toggle source
# File lib/jekyll/collection.rb, line 213
def container
  @container ||= site.config["collections_dir"]
end
determine_sort_order(sort_key, apples, olives) click to toggle source
# File lib/jekyll/collection.rb, line 253
def determine_sort_order(sort_key, apples, olives)
  apple_property, apple_document = apples
  olive_property, olive_document = olives

  if apple_property.nil? && !olive_property.nil?
    order_with_warning(sort_key, apple_document, 1)
  elsif !apple_property.nil? && olive_property.nil?
    order_with_warning(sort_key, olive_document, -1)
  else
    apple_property <=> olive_property
  end
end
order_with_warning(sort_key, document, order) click to toggle source
# File lib/jekyll/collection.rb, line 266
def order_with_warning(sort_key, document, order)
  Jekyll.logger.warn "Sort warning:", "'#{sort_key}' not defined in #{document.relative_path}"
  order
end
read_document(full_path) click to toggle source
# File lib/jekyll/collection.rb, line 217
def read_document(full_path)
  doc = Document.new(full_path, :site => site, :collection => self)
  doc.read
  docs << doc if site.unpublished || doc.published?
end
read_static_file(file_path, full_path) click to toggle source
# File lib/jekyll/collection.rb, line 295
def read_static_file(file_path, full_path)
  relative_dir = Jekyll.sanitized_path(
    relative_directory,
    File.dirname(file_path)
  ).chomp("/.")

  files << StaticFile.new(
    site,
    site.source,
    relative_dir,
    File.basename(full_path),
    self
  )
end
rearrange_docs!() click to toggle source

Rearrange documents within the ‘docs` array as listed in the `metadata` array.

Involves converting the two arrays into hashes based on relative_paths as keys first, then merging them to remove duplicates and finally retrieving the Document instances from the merged array.

# File lib/jekyll/collection.rb, line 276
def rearrange_docs!
  docs_table   = {}
  custom_order = {}

  # pre-sort to normalize default array across platforms and then proceed to create a Hash
  # from that sorted array.
  docs.sort.each do |doc|
    docs_table[doc.relative_path] = doc
  end

  metadata["order"].each do |entry|
    custom_order[File.join(relative_directory, entry)] = nil
  end

  result = Jekyll::Utils.deep_merge_hashes(custom_order, docs_table).values
  result.compact!
  self.docs = result
end
sort_docs!() click to toggle source
# File lib/jekyll/collection.rb, line 223
def sort_docs!
  if metadata["order"].is_a?(Array)
    rearrange_docs!
  elsif metadata["sort_by"].is_a?(String)
    sort_docs_by_key!
  else
    docs.sort!
  end
end
sort_docs_by_key!() click to toggle source

A custom sort function based on Schwartzian transform Refer byparker.com/blog/2017/schwartzian-transform-faster-sorting/ for details

# File lib/jekyll/collection.rb, line 235
def sort_docs_by_key!
  meta_key = metadata["sort_by"]
  # Modify `docs` array to cache document's property along with the Document instance
  docs.map! { |doc| [doc.data[meta_key], doc] }.sort! do |apples, olives|
    order = determine_sort_order(meta_key, apples, olives)

    # Fall back to `Document#<=>` if the properties were equal or were non-sortable
    # Otherwise continue with current sort-order
    if order.nil? || order.zero?
      apples[-1] <=> olives[-1]
    else
      order
    end

    # Finally restore the `docs` array with just the Document objects themselves
  end.map!(&:last)
end