class Jekyll::Document
Constants
- DATELESS_FILENAME_MATCHER
- DATE_FILENAME_MATCHER
- YAML_FRONT_MATTER_REGEXP
Attributes
Public Class Methods
Create a new Document.
path - the path to the file relations - a hash with keys :site and :collection, the values of which
are the Jekyll::Site and Jekyll::Collection to which this Document belong.
Returns nothing.
# File lib/jekyll/document.rb, line 21 def initialize(path, relations = {}) @site = relations[:site] @path = path @extname = File.extname(path) @collection = relations[:collection] @has_yaml_header = nil if draft? categories_from_path("_drafts") else categories_from_path(collection.relative_directory) end data.default_proc = proc do |_, key| site.frontmatter_defaults.find(relative_path, collection.label, key) end trigger_hooks(:post_init) end
Public Instance Methods
Compare this document against another document. Comparison is a comparison between the 2 paths of the documents.
Returns -1, 0, +1 or nil depending on whether this doc's path is less than,
equal or greater than the other doc's path. See String#<=> for more details.
# File lib/jekyll/document.rb, line 366 def <=>(other) return nil unless other.respond_to?(:data) cmp = data["date"] <=> other.data["date"] cmp = path <=> other.path if cmp.nil? || cmp.zero? cmp end
# File lib/jekyll/document.rb, line 213 def [](key) data[key] end
Determine whether the document is an asset file. Asset files include CoffeeScript files and Sass/SCSS files.
Returns true if the extname belongs to the set of extensions
that asset files use.
# File lib/jekyll/document.rb, line 145 def asset_file? sass_file? || coffeescript_file? end
The base filename of the document.
Returns the base filename of the document.
# File lib/jekyll/document.rb, line 113 def basename @basename ||= File.basename(path) end
The base filename of the document, without the file extname.
Returns the basename without the file extname.
# File lib/jekyll/document.rb, line 106 def basename_without_ext @basename_without_ext ||= File.basename(path, ".*") end
Add superdirectories of the special_dir to categories. In the case of es/_posts, 'es' is added as a category. In the case of _posts/es, 'es' is NOT added as a category.
Returns nothing.
# File lib/jekyll/document.rb, line 315 def categories_from_path(special_dir) superdirs = relative_path.sub(%r!#{special_dir}(.*)!, "") .split(File::SEPARATOR) .reject do |c| c.empty? || c.eql?(special_dir) || c.eql?(basename) end merge_data!({ "categories" => superdirs }, :source => "file path") end
Produces a “cleaned” relative path. The “cleaned” relative path is the relative path without the extname
and with the collection's directory removed as well.
This method is useful when building the URL of the document.
Examples:
When relative_path is "_methods/site/generate.md": cleaned_relative_path # => "/site/generate"
Returns the cleaned relative path of the document.
# File lib/jekyll/document.rb, line 128 def cleaned_relative_path @cleaned_relative_path ||= relative_path[0..-extname.length - 1].sub(collection.relative_directory, "") end
Determine whether the document is a CoffeeScript file.
Returns true if extname == .coffee, false otherwise.
# File lib/jekyll/document.rb, line 159 def coffeescript_file? ".coffee" == extname end
Fetch the Document's data.
Returns a Hash containing the data. An empty hash is returned if
no data was read.
# File lib/jekyll/document.rb, line 45 def data @data ||= {} end
# File lib/jekyll/document.rb, line 69 def date data["date"] ||= (draft? ? source_file_mtime : site.time) end
The full path to the output file.
base_directory - the base path of the output directory
Returns the full path to the output file of this document.
# File lib/jekyll/document.rb, line 222 def destination(base_directory) dest = site.in_dest_dir(base_directory) path = site.in_dest_dir(dest, URL.unescape_path(url)) if url.end_with? "/" path = File.join(path, "index.html") else path << output_ext unless path.end_with? output_ext end path end
Returns whether the document is a draft. This is only the case if the document is in the 'posts' collection but in a different directory than '_posts'.
Returns whether the document is a draft.
# File lib/jekyll/document.rb, line 82 def draft? data["draft"] ||= relative_path.index(collection.relative_directory).nil? && collection.label == "posts" end
The Document #excerpt_separator, from the YAML Front-Matter or site default #excerpt_separator value
Returns the document #excerpt_separator
# File lib/jekyll/document.rb, line 386 def excerpt_separator (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s end
Whether to generate an excerpt
Returns true if the excerpt separator is configured.
# File lib/jekyll/document.rb, line 393 def generate_excerpt? !excerpt_separator.empty? end
# File lib/jekyll/document.rb, line 416 def id @id ||= File.join(File.dirname(url), (data["slug"] || basename_without_ext).to_s) end
The inspect string for this document. Includes the relative path and the collection label.
Returns the inspect string for this document.
# File lib/jekyll/document.rb, line 350 def inspect "#<Jekyll::Document #{relative_path} collection=#{collection.label}>" end
Merge some data in with this document's data.
Returns the merged data.
# File lib/jekyll/document.rb, line 52 def merge_data!(other, source: "YAML front matter") if other.key?("categories") && !other["categories"].nil? if other["categories"].is_a?(String) other["categories"] = other["categories"].split(" ").map(&:strip) end other["categories"] = (data["categories"] || []) | other["categories"] end Utils.deep_merge_hashes!(data, other) if data.key?("date") && !data["date"].is_a?(Time) data["date"] = Utils.parse_date( data["date"].to_s, "Document '#{relative_path}' does not have a valid date in the #{source}." ) end data end
Override of #method_missing to check in @data for the key.
# File lib/jekyll/document.rb, line 434 def method_missing(method, *args, &blck) if data.key?(method.to_s) Jekyll::Deprecator.deprecation_message "Document##{method} is now a key " "in the #data hash." Jekyll::Deprecator.deprecation_message "Called by #{caller.first}." data[method.to_s] else super end end
# File lib/jekyll/document.rb, line 397 def next_doc pos = collection.docs.index { |post| post.equal?(self) } if pos && pos < collection.docs.length - 1 collection.docs[pos + 1] end end
The output extension of the document.
Returns the output extension
# File lib/jekyll/document.rb, line 99 def output_ext Jekyll::Renderer.new(site, self).output_ext end
The permalink for this Document. Permalink is set via the data Hash.
Returns the permalink or nil if no permalink was set in the data.
# File lib/jekyll/document.rb, line 198 def permalink data && data.is_a?(Hash) && data["permalink"] end
Determine whether the file should be placed into layouts.
Returns false if the document is either an asset file or a yaml file,
true otherwise.
# File lib/jekyll/document.rb, line 175 def place_in_layout? !(asset_file? || yaml_file?) end
# File lib/jekyll/document.rb, line 324 def populate_categories merge_data!({ "categories" => ( Array(data["categories"]) + Utils.pluralized_array_from_hash(data, "category", "categories") ).map(&:to_s).flatten.uniq }) end
# File lib/jekyll/document.rb, line 289 def post_read if relative_path =~ DATE_FILENAME_MATCHER date, slug, ext = Regexp.last_match.captures if !data["date"] || data["date"].to_i == site.time.to_i merge_data!({ "date" => date }, :source => "filename") end elsif relative_path =~ DATELESS_FILENAME_MATCHER slug, ext = Regexp.last_match.captures end # Try to ensure the user gets a title. data["title"] ||= Utils.titleize_slug(slug) # Only overwrite slug & ext if they aren't specified. data["slug"] ||= slug data["ext"] ||= ext populate_categories populate_tags generate_excerpt end
# File lib/jekyll/document.rb, line 404 def previous_doc pos = collection.docs.index { |post| post.equal?(self) } if pos && pos > 0 collection.docs[pos - 1] end end
Whether the file is published or not, as indicated in YAML front-matter
Returns 'false' if the 'published' key is specified in the YAML front-matter and is 'false'. Otherwise returns 'true'.
# File lib/jekyll/document.rb, line 250 def published? !(data.key?("published") && data["published"] == false) end
Read in the file and assign the content and data based on the file contents. Merge the frontmatter of the file with the frontmatter default values
Returns nothing.
# File lib/jekyll/document.rb, line 259 def read(opts = {}) Jekyll.logger.debug "Reading:", relative_path if yaml_file? @data = SafeYAML.load_file(path) else begin defaults = @site.frontmatter_defaults.all( relative_path, collection.label.to_sym ) merge_data!(defaults, :source => "front matter defaults") unless defaults.empty? self.content = File.read(path, Utils.merged_file_read_opts(site, opts)) if content =~ YAML_FRONT_MATTER_REGEXP self.content = $POSTMATCH data_file = SafeYAML.load(Regexp.last_match(1)) merge_data!(data_file, :source => "YAML front matter") if data_file end post_read rescue SyntaxError => e Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{e.message}" rescue => e raise e if e.is_a? Jekyll::Errors::FatalException Jekyll.logger.error "Error:", "could not read file #{path}: #{e.message}" end end end
The path to the document, relative to the site source.
Returns a String path which represents the relative path
from the site source to this document
# File lib/jekyll/document.rb, line 91 def relative_path @relative_path ||= Pathname.new(path) .relative_path_from(Pathname.new(site.source)).to_s end
Determine whether the file should be rendered with Liquid.
Returns false if the document is either an asset file or a yaml file,
true otherwise.
# File lib/jekyll/document.rb, line 167 def render_with_liquid? !(coffeescript_file? || yaml_file?) end
Override of normal respond_to? to match #method_missing's logic for looking in @data.
# File lib/jekyll/document.rb, line 429 def respond_to?(method, include_private = false) data.key?(method.to_s) || super end
Determine whether the document is a Sass file.
Returns true if extname == .sass or .scss, false otherwise.
# File lib/jekyll/document.rb, line 152 def sass_file? %w(.sass .scss).include?(extname) end
# File lib/jekyll/document.rb, line 73 def source_file_mtime @source_file_mtime ||= File.mtime(path) end
Create a Liquid-understandable version of this Document.
Returns a Hash representing this Document's data.
# File lib/jekyll/document.rb, line 342 def to_liquid @to_liquid ||= Drops::DocumentDrop.new(self) end
The string representation for this document.
Returns the content of the document
# File lib/jekyll/document.rb, line 357 def to_s output || content || "NO CONTENT" end
# File lib/jekyll/document.rb, line 411 def trigger_hooks(hook_name, *args) Jekyll::Hooks.trigger collection.label.to_sym, hook_name, self, *args if collection Jekyll::Hooks.trigger :documents, hook_name, self, *args end
Construct a Hash of key-value pairs which contain a mapping between
a key in the URL template and the corresponding value for this document.
Returns the Hash of key-value pairs for replacement in the URL.
# File lib/jekyll/document.rb, line 190 def url_placeholders @url_placeholders ||= Drops::UrlDrop.new(self) end
Write the generated Document file to the destination directory.
dest - The String path to the destination dir.
Returns nothing.
# File lib/jekyll/document.rb, line 238 def write(dest) path = destination(dest) FileUtils.mkdir_p(File.dirname(path)) File.write(path, output, :mode => "wb") trigger_hooks(:post_write) end
Determine whether this document should be written. Based on the Collection to which it belongs.
True if the document has a collection and if that collection's write?
method returns true, otherwise false.
# File lib/jekyll/document.rb, line 378 def write? collection && collection.write? end
Determine whether the document is a YAML file.
Returns true if the extname is either .yml or .yaml, false otherwise.
# File lib/jekyll/document.rb, line 136 def yaml_file? %w(.yaml .yml).include?(extname) end
Private Instance Methods
# File lib/jekyll/document.rb, line 446 def generate_excerpt if generate_excerpt? data["excerpt"] ||= Jekyll::Excerpt.new(self) end end