Class: Jekyll::Document
- Inherits:
-
Object
- Object
- Jekyll::Document
- Includes:
- Comparable
- Defined in:
- lib/jekyll/document.rb
Constant Summary collapse
- YAML_FRONT_MATTER_REGEXP =
/\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
- DATELESS_FILENAME_MATCHER =
/^(.+\/)*(.*)(\.[^.]+)$/
- DATE_FILENAME_MATCHER =
/^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
Instance Attribute Summary collapse
-
#collection ⇒ Object
readonly
Returns the value of attribute collection.
-
#content ⇒ Object
Returns the value of attribute content.
-
#extname ⇒ Object
readonly
Returns the value of attribute extname.
-
#output ⇒ Object
Returns the value of attribute output.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#site ⇒ Object
readonly
Returns the value of attribute site.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
Compare this document against another document.
- #[](key) ⇒ Object
-
#asset_file? ⇒ Boolean
Determine whether the document is an asset file.
-
#basename ⇒ Object
The base filename of the document.
-
#basename_without_ext ⇒ Object
The base filename of the document, without the file extname.
-
#categories_from_path(special_dir) ⇒ Object
Add superdirectories of the special_dir to categories.
-
#cleaned_relative_path ⇒ Object
Produces a “cleaned” relative path.
-
#coffeescript_file? ⇒ Boolean
Determine whether the document is a CoffeeScript file.
-
#data ⇒ Object
Fetch the Document’s data.
- #date ⇒ Object
-
#destination(base_directory) ⇒ Object
The full path to the output file.
-
#draft? ⇒ Boolean
Returns whether the document is a draft.
-
#excerpt_separator ⇒ Object
The Document excerpt_separator, from the YAML Front-Matter or site default excerpt_separator value.
-
#generate_excerpt? ⇒ Boolean
Whether to generate an excerpt.
- #id ⇒ Object
-
#initialize(path, relations = {}) ⇒ Document
constructor
Create a new Document.
-
#inspect ⇒ Object
The inspect string for this document.
-
#merge_data!(other, source: "YAML front matter") ⇒ Object
Merge some data in with this document’s data.
-
#method_missing(method, *args, &blck) ⇒ Object
Override of method_missing to check in @data for the key.
- #next_doc ⇒ Object
-
#output_ext ⇒ Object
The output extension of the document.
-
#permalink ⇒ Object
The permalink for this Document.
-
#place_in_layout? ⇒ Boolean
Determine whether the file should be placed into layouts.
- #populate_categories ⇒ Object
- #populate_tags ⇒ Object
- #post_read ⇒ Object
- #previous_doc ⇒ Object
-
#published? ⇒ Boolean
Whether the file is published or not, as indicated in YAML front-matter.
-
#read(opts = {}) ⇒ Object
Read in the file and assign the content and data based on the file contents.
-
#related_posts ⇒ Object
Calculate related posts.
-
#relative_path ⇒ Object
The path to the document, relative to the site source.
-
#render_with_liquid? ⇒ Boolean
Determine whether the file should be rendered with Liquid.
-
#respond_to?(method, include_private = false) ⇒ Boolean
Override of normal respond_to? to match method_missing’s logic for looking in @data.
-
#sass_file? ⇒ Boolean
Determine whether the document is a Sass file.
-
#to_liquid ⇒ Object
Create a Liquid-understandable version of this Document.
-
#to_s ⇒ Object
The string representation for this document.
- #trigger_hooks(hook_name, *args) ⇒ Object
-
#url ⇒ Object
The computed URL for the document.
-
#url_placeholders ⇒ Object
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.
-
#url_template ⇒ Object
The URL template where the document would be accessible.
-
#write(dest) ⇒ Object
Write the generated Document file to the destination directory.
-
#write? ⇒ Boolean
Determine whether this document should be written.
-
#yaml_file? ⇒ Boolean
Determine whether the document is a YAML file.
Constructor Details
#initialize(path, relations = {}) ⇒ Document
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.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/jekyll/document.rb', line 22 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 |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &blck) ⇒ Object
Override of method_missing to check in @data for the key.
430 431 432 433 434 435 436 437 438 |
# File 'lib/jekyll/document.rb', line 430 def method_missing(method, *args, &blck) if data.key?(method.to_s) Jekyll.logger.warn "Deprecation:", "Document##{method} is now a key in the #data hash." Jekyll.logger.warn "", "Called by #{caller.first}." data[method.to_s] else super end end |
Instance Attribute Details
#collection ⇒ Object (readonly)
Returns the value of attribute collection.
7 8 9 |
# File 'lib/jekyll/document.rb', line 7 def collection @collection end |
#content ⇒ Object
Returns the value of attribute content.
8 9 10 |
# File 'lib/jekyll/document.rb', line 8 def content @content end |
#extname ⇒ Object (readonly)
Returns the value of attribute extname.
7 8 9 |
# File 'lib/jekyll/document.rb', line 7 def extname @extname end |
#output ⇒ Object
Returns the value of attribute output.
8 9 10 |
# File 'lib/jekyll/document.rb', line 8 def output @output end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
7 8 9 |
# File 'lib/jekyll/document.rb', line 7 def path @path end |
#site ⇒ Object (readonly)
Returns the value of attribute site.
7 8 9 |
# File 'lib/jekyll/document.rb', line 7 def site @site end |
Instance Method Details
#<=>(other) ⇒ Object
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.
358 359 360 361 362 363 |
# File 'lib/jekyll/document.rb', line 358 def <=>(other) return nil unless other.respond_to?(:data) cmp = data['date'] <=> other.data['date'] cmp = path <=> other.path if cmp.nil? || cmp == 0 cmp end |
#[](key) ⇒ Object
208 209 210 |
# File 'lib/jekyll/document.rb', line 208 def [](key) data[key] end |
#asset_file? ⇒ Boolean
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.
140 141 142 |
# File 'lib/jekyll/document.rb', line 140 def asset_file? sass_file? || coffeescript_file? end |
#basename ⇒ Object
The base filename of the document.
Returns the base filename of the document.
108 109 110 |
# File 'lib/jekyll/document.rb', line 108 def basename @basename ||= File.basename(path) end |
#basename_without_ext ⇒ Object
The base filename of the document, without the file extname.
Returns the basename without the file extname.
101 102 103 |
# File 'lib/jekyll/document.rb', line 101 def basename_without_ext @basename_without_ext ||= File.basename(path, '.*') end |
#categories_from_path(special_dir) ⇒ Object
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.
310 311 312 313 314 315 |
# File 'lib/jekyll/document.rb', line 310 def categories_from_path(special_dir) superdirs = relative_path.sub(/#{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 |
#cleaned_relative_path ⇒ Object
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.
123 124 125 126 |
# File 'lib/jekyll/document.rb', line 123 def cleaned_relative_path @cleaned_relative_path ||= relative_path[0..-extname.length - 1].sub(collection.relative_directory, "") end |
#coffeescript_file? ⇒ Boolean
Determine whether the document is a CoffeeScript file.
Returns true if extname == .coffee, false otherwise.
154 155 156 |
# File 'lib/jekyll/document.rb', line 154 def coffeescript_file? '.coffee'.eql?(extname) end |
#data ⇒ Object
Fetch the Document’s data.
Returns a Hash containing the data. An empty hash is returned if
no data was read.
46 47 48 |
# File 'lib/jekyll/document.rb', line 46 def data @data ||= {} end |
#date ⇒ Object
70 71 72 |
# File 'lib/jekyll/document.rb', line 70 def date data['date'] ||= site.time end |
#destination(base_directory) ⇒ Object
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.
217 218 219 220 221 222 223 224 225 226 |
# File 'lib/jekyll/document.rb', line 217 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 |
#draft? ⇒ Boolean
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.
79 80 81 |
# File 'lib/jekyll/document.rb', line 79 def draft? data['draft'] ||= relative_path.index(collection.relative_directory).nil? && collection.label == "posts" end |
#excerpt_separator ⇒ Object
The Document excerpt_separator, from the YAML Front-Matter or site default excerpt_separator value
Returns the document excerpt_separator
378 379 380 |
# File 'lib/jekyll/document.rb', line 378 def excerpt_separator (data['excerpt_separator'] || site.config['excerpt_separator']).to_s end |
#generate_excerpt? ⇒ Boolean
Whether to generate an excerpt
Returns true if the excerpt separator is configured.
385 386 387 |
# File 'lib/jekyll/document.rb', line 385 def generate_excerpt? !excerpt_separator.empty? end |
#id ⇒ Object
412 413 414 |
# File 'lib/jekyll/document.rb', line 412 def id @id ||= File.join(File.dirname(url), (data['slug'] || basename_without_ext).to_s) end |
#inspect ⇒ Object
The inspect string for this document. Includes the relative path and the collection label.
Returns the inspect string for this document.
342 343 344 |
# File 'lib/jekyll/document.rb', line 342 def inspect "#<Jekyll::Document #{relative_path} collection=#{collection.label}>" end |
#merge_data!(other, source: "YAML front matter") ⇒ Object
Merge some data in with this document’s data.
Returns the merged data.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/jekyll/document.rb', line 53 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 |
#next_doc ⇒ Object
389 390 391 392 393 394 395 396 |
# File 'lib/jekyll/document.rb', line 389 def next_doc pos = collection.docs.index { |post| post.equal?(self) } if pos && pos < collection.docs.length - 1 collection.docs[pos + 1] else nil end end |
#output_ext ⇒ Object
The output extension of the document.
Returns the output extension
94 95 96 |
# File 'lib/jekyll/document.rb', line 94 def output_ext Jekyll::Renderer.new(site, self).output_ext end |
#permalink ⇒ Object
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.
193 194 195 |
# File 'lib/jekyll/document.rb', line 193 def permalink data && data.is_a?(Hash) && data['permalink'] end |
#place_in_layout? ⇒ Boolean
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.
170 171 172 |
# File 'lib/jekyll/document.rb', line 170 def place_in_layout? !(asset_file? || yaml_file?) end |
#populate_categories ⇒ Object
317 318 319 320 321 322 323 |
# File 'lib/jekyll/document.rb', line 317 def populate_categories merge_data!({ 'categories' => ( Array(data['categories']) + Utils.pluralized_array_from_hash(data, 'category', 'categories') ).map(&:to_s).flatten.uniq }) end |
#populate_tags ⇒ Object
325 326 327 328 329 |
# File 'lib/jekyll/document.rb', line 325 def merge_data!({ "tags" => Utils.pluralized_array_from_hash(data, "tag", "tags").flatten }) end |
#post_read ⇒ Object
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/jekyll/document.rb', line 284 def post_read if relative_path =~ DATE_FILENAME_MATCHER date, slug, ext = $2, $3, $4 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 = $2, $3 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 generate_excerpt end |
#previous_doc ⇒ Object
398 399 400 401 402 403 404 405 |
# File 'lib/jekyll/document.rb', line 398 def previous_doc pos = collection.docs.index { |post| post.equal?(self) } if pos && pos > 0 collection.docs[pos - 1] else nil end end |
#published? ⇒ Boolean
Whether the file is published or not, as indicated in YAML front-matter
Returns true if the ‘published’ key is specified in the YAML front-matter and not ‘false`.
246 247 248 |
# File 'lib/jekyll/document.rb', line 246 def published? !(data.key?('published') && data['published'] == false) end |
#read(opts = {}) ⇒ Object
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.
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/jekyll/document.rb', line 255 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.}" rescue Exception => e if e.is_a? Jekyll::Errors::FatalException raise e end Jekyll.logger.error "Error:", "could not read file #{path}: #{e.}" end end end |
#related_posts ⇒ Object
Calculate related posts.
Returns an Array of related Posts.
419 420 421 |
# File 'lib/jekyll/document.rb', line 419 def Jekyll::RelatedPosts.new(self).build end |
#relative_path ⇒ Object
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
87 88 89 |
# File 'lib/jekyll/document.rb', line 87 def relative_path @relative_path ||= Pathname.new(path).relative_path_from(Pathname.new(site.source)).to_s end |
#render_with_liquid? ⇒ Boolean
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.
162 163 164 |
# File 'lib/jekyll/document.rb', line 162 def render_with_liquid? !(coffeescript_file? || yaml_file?) end |
#respond_to?(method, include_private = false) ⇒ Boolean
Override of normal respond_to? to match method_missing’s logic for looking in @data.
425 426 427 |
# File 'lib/jekyll/document.rb', line 425 def respond_to?(method, include_private = false) data.key?(method.to_s) || super end |
#sass_file? ⇒ Boolean
Determine whether the document is a Sass file.
Returns true if extname == .sass or .scss, false otherwise.
147 148 149 |
# File 'lib/jekyll/document.rb', line 147 def sass_file? %w(.sass .scss).include?(extname) end |
#to_liquid ⇒ Object
Create a Liquid-understandable version of this Document.
Returns a Hash representing this Document’s data.
334 335 336 |
# File 'lib/jekyll/document.rb', line 334 def to_liquid @to_liquid ||= Drops::DocumentDrop.new(self) end |
#to_s ⇒ Object
The string representation for this document.
Returns the content of the document
349 350 351 |
# File 'lib/jekyll/document.rb', line 349 def to_s output || content || 'NO CONTENT' end |
#trigger_hooks(hook_name, *args) ⇒ Object
407 408 409 410 |
# File 'lib/jekyll/document.rb', line 407 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 |
#url ⇒ Object
The computed URL for the document. See ‘Jekyll::URL#to_s` for more details.
Returns the computed URL for the document.
200 201 202 203 204 205 206 |
# File 'lib/jekyll/document.rb', line 200 def url @url = URL.new({ :template => url_template, :placeholders => url_placeholders, :permalink => permalink }).to_s end |
#url_placeholders ⇒ Object
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.
185 186 187 |
# File 'lib/jekyll/document.rb', line 185 def url_placeholders @url_placeholders ||= Drops::UrlDrop.new(self) end |
#url_template ⇒ Object
The URL template where the document would be accessible.
Returns the URL template for the document.
177 178 179 |
# File 'lib/jekyll/document.rb', line 177 def url_template collection.url_template end |
#write(dest) ⇒ Object
Write the generated Document file to the destination directory.
dest - The String path to the destination dir.
Returns nothing.
233 234 235 236 237 238 239 240 241 |
# File 'lib/jekyll/document.rb', line 233 def write(dest) path = destination(dest) FileUtils.mkdir_p(File.dirname(path)) File.open(path, 'wb') do |f| f.write(output) end trigger_hooks(:post_write) end |
#write? ⇒ Boolean
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.
370 371 372 |
# File 'lib/jekyll/document.rb', line 370 def write? collection && collection.write? end |
#yaml_file? ⇒ Boolean
Determine whether the document is a YAML file.
Returns true if the extname is either .yml or .yaml, false otherwise.
131 132 133 |
# File 'lib/jekyll/document.rb', line 131 def yaml_file? %w(.yaml .yml).include?(extname) end |