class Jekyll::Site

Attributes

baseurl[RW]
categories[RW]
config[RW]
converters[RW]
data[RW]
data_sources[RW]
dest[RW]
exclude[RW]
file_read_opts[RW]
future[RW]
generators[RW]
include[RW]
keep_files[RW]
layouts[RW]
limit_posts[RW]
lsi[RW]
pages[RW]
plugins[RW]
posts[RW]
pygments[RW]
safe[RW]
show_drafts[RW]
source[RW]
static_files[RW]
tags[RW]
time[RW]

Public Class Methods

new(config) click to toggle source

Public: Initialize a new Site.

config - A Hash containing site configuration details.

# File lib/jekyll/site.rb, line 13
def initialize(config)
  self.config          = config.clone

  %w[safe lsi pygments baseurl exclude include future show_drafts limit_posts keep_files].each do |opt|
    self.send("#{opt}=", config[opt])
  end

  self.source          = File.expand_path(config['source'])
  self.dest            = File.expand_path(config['destination'])
  self.plugins         = plugins_path
  self.permalink_style = config['permalink'].to_sym

  self.file_read_opts = {}
  self.file_read_opts[:encoding] = config['encoding'] if config['encoding']

  self.reset
  self.setup
end

Public Instance Methods

aggregate_post_info(post) click to toggle source

Aggregate post information

post - The Post object to aggregate information for

Returns nothing

# File lib/jekyll/site.rb, line 401
def aggregate_post_info(post)
  self.posts << post
  post.categories.each { |c| self.categories[c] << post }
  post.tags.each { |c| self.tags[c] << post }
end
cleanup() click to toggle source

Remove orphaned files and empty directories in destination.

Returns nothing.

# File lib/jekyll/site.rb, line 269
def cleanup
  site_cleaner.cleanup!
end
each_site_file() { |item| ... } click to toggle source
# File lib/jekyll/site.rb, line 419
def each_site_file
  %w(posts pages static_files).each do |type|
    self.send(type).each do |item|
      yield item
    end
  end
end
ensure_not_in_dest() click to toggle source

Check that the destination dir isn’t the source dir or a directory parent to the source dir.

# File lib/jekyll/site.rb, line 89
def ensure_not_in_dest
  dest = Pathname.new(self.dest)
  Pathname.new(self.source).ascend do |path|
    if path == dest
      raise FatalException.new "Destination directory cannot be or contain the Source directory."
    end
  end
end
filter_entries(entries) click to toggle source

Filter out any files/directories that are hidden or backup files (start with “.” or “#” or end with “~”), or contain site content (start with “_”), or are excluded in the site configuration, unless they are web server files such as ‘.htaccess’.

entries - The Array of String file/directory entries to filter.

Returns the Array of filtered entries.

# File lib/jekyll/site.rb, line 343
def filter_entries(entries)
  entries.reject do |e|
    unless self.include.glob_include?(e)
      ['.', '_', '#'].include?(e[0..0]) ||
      e[-1..-1] == '~' ||
      self.exclude.glob_include?(e) ||
      (File.symlink?(e) && self.safe)
    end
  end
end
generate() click to toggle source

Run each of the Generators.

Returns nothing.

# File lib/jekyll/site.rb, line 243
def generate
  self.generators.each do |generator|
    generator.generate(self)
  end
end
getConverterImpl(klass) click to toggle source

Get the implementation class for the given Converter.

klass - The Class of the Converter to fetch.

Returns the Converter instance implementing the given Converter.

# File lib/jekyll/site.rb, line 359
def getConverterImpl(klass)
  matches = self.converters.select { |c| c.class == klass }
  if impl = matches.first
    impl
  else
    raise "Converter implementation not found for #{klass}"
  end
end
get_entries(dir, subfolder) click to toggle source

Read the entries from a particular directory for processing

dir - The String relative path of the directory to read subfolder - The String directory to read

Returns the list of entries to process

# File lib/jekyll/site.rb, line 389
def get_entries(dir, subfolder)
  base = File.join(self.source, dir, subfolder)
  return [] unless File.exists?(base)
  entries = Dir.chdir(base) { filter_entries(Dir['**/*']) }
  entries.delete_if { |e| File.directory?(File.join(base, e)) }
end
instantiate_subclasses(klass) click to toggle source

Create array of instances of the subclasses of the class or module

passed in as argument.

klass - class or module containing the subclasses which should be

instantiated

Returns array of instances of subclasses of parameter

# File lib/jekyll/site.rb, line 375
def instantiate_subclasses(klass)
  klass.subclasses.select do |c|
    !self.safe || c.safe
  end.sort.map do |c|
    c.new(self.config)
  end
end
load_data_sources() click to toggle source

Load external data sources to @data_sources

Returns nothing

# File lib/jekyll/site.rb, line 226
def load_data_sources
  self.config['data_sources'] && self.config['data_sources'].each do |data_source_config|
    if data_source_config['name'] !~ /^\w+$/
      raise FatalException.new "Bad data source name: #{data_source_config['name']}. Only letters or digits allowed in data source name."
    end

    # create driver
    driver_name = data_source_config['type'].split('_').collect!{ |w| w.capitalize }.join + 'Driver'
    driver = Jekyll::Drivers.const_get(driver_name).new(data_source_config)

    @data_sources[data_source_config['name']] = driver.load
  end
end
plugins_path() click to toggle source

Internal: Setup the plugin search path

Returns an Array of plugin search paths

# File lib/jekyll/site.rb, line 101
def plugins_path
  if (config['plugins'] == Jekyll::Configuration::DEFAULTS['plugins'])
    [File.join(self.source, config['plugins'])]
  else
    Array(config['plugins']).map { |d| File.expand_path(d) }
  end
end
post_attr_hash(post_attr) click to toggle source

Construct a Hash of Posts indexed by the specified Post attribute.

post_attr - The String name of the Post attribute.

Examples

post_attr_hash('categories')
# => { 'tech' => [<Post A>, <Post B>],
#      'ruby' => [<Post B>] }

Returns the Hash: { attr => posts } where

attr  - One of the values for the requested attribute.
posts - The Array of Posts with the given attr value.
# File lib/jekyll/site.rb, line 293
def post_attr_hash(post_attr)
  # Build a hash map based on the specified post attribute ( post attr =>
  # array of posts ) then sort each array in reverse order.
  hash = Hash.new { |hsh, key| hsh[key] = Array.new }
  self.posts.each { |p| p.send(post_attr.to_sym).each { |t| hash[t] << p } }
  hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a } }
  hash
end
process() click to toggle source

Public: Read, process, and write this Site to output.

Returns nothing.

# File lib/jekyll/site.rb, line 35
def process
  self.reset
  self.read
  self.generate
  self.render
  self.cleanup
  self.write
end
read() click to toggle source

Read Site data from disk and load it into internal data structures.

Returns nothing.

# File lib/jekyll/site.rb, line 112
def read
  self.read_layouts
  self.read_directories
  self.read_data(config['data_source'])
  self.load_data_sources
end
read_data(dir) click to toggle source

Read and parse all yaml files under <source>/<dir>

Returns nothing

# File lib/jekyll/site.rb, line 207
def read_data(dir)
  base = File.join(self.source, dir)
  return unless File.directory?(base) && (!self.safe || !File.symlink?(base))

  entries = Dir.chdir(base) { Dir['*.{yaml,yml}'] }
  entries.delete_if { |e| File.directory?(File.join(base, e)) }

  entries.each do |entry|
    path = File.join(self.source, dir, entry)
    next if File.symlink?(path) && self.safe

    key = sanitize_filename(File.basename(entry, '.*'))
    self.data[key] = YAML.safe_load_file(path)
  end
end
read_directories(dir = '') click to toggle source

Recursively traverse directories to find posts, pages and static files that will become part of the site according to the rules in filter_entries.

dir - The String relative path of the directory to read. Default: ”.

Returns nothing.

# File lib/jekyll/site.rb, line 142
def read_directories(dir = '')
  base = File.join(self.source, dir)
  entries = Dir.chdir(base) { filter_entries(Dir.entries('.')) }

  self.read_posts(dir)
  self.read_drafts(dir) if self.show_drafts
  self.posts.sort!
  limit_posts! if limit_posts > 0 # limit the posts if :limit_posts option is set

  entries.each do |f|
    f_abs = File.join(base, f)
    if File.directory?(f_abs)
      f_rel = File.join(dir, f)
      read_directories(f_rel) unless self.dest.sub(/\/$/, '') == f_abs
    elsif has_yaml_header?(f_abs)
      pages << Page.new(self, self.source, dir, f)
    else
      static_files << StaticFile.new(self, self.source, dir, f)
    end
  end
end
read_drafts(dir) click to toggle source

Read all the files in <source>/<dir>/_drafts and create a new Post object with each one.

dir - The String relative path of the directory to read.

Returns nothing.

# File lib/jekyll/site.rb, line 191
def read_drafts(dir)
  entries = get_entries(dir, '_drafts')

  # first pass processes, but does not yet render draft content
  entries.each do |f|
    if Draft.valid?(f)
      draft = Draft.new(self, self.source, dir, f)

      aggregate_post_info(draft)
    end
  end
end
read_layouts() click to toggle source

Read all the files in <source>/<layouts> and create a new Layout object with each one.

Returns nothing.

# File lib/jekyll/site.rb, line 123
def read_layouts
  base = File.join(self.source, self.config['layouts'])
  return unless File.exists?(base)
  entries = []
  Dir.chdir(base) { entries = filter_entries(Dir['**/*.*']) }

  entries.each do |f|
    name = f.split(".")[0..-2].join(".")
    self.layouts[name] = Layout.new(self, base, f)
  end
end
read_posts(dir) click to toggle source

Read all the files in <source>/<dir>/_posts and create a new Post object with each one.

dir - The String relative path of the directory to read.

Returns nothing.

# File lib/jekyll/site.rb, line 170
def read_posts(dir)
  entries = get_entries(dir, '_posts')

  # first pass processes, but does not yet render post content
  entries.each do |f|
    if Post.valid?(f)
      post = Post.new(self, self.source, dir, f)

      if post.published && (self.future || post.date <= self.time)
        aggregate_post_info(post)
      end
    end
  end
end
render() click to toggle source

Render the site to the destination.

Returns nothing.

# File lib/jekyll/site.rb, line 252
def render
  relative_permalinks_deprecation_method

  payload = site_payload
  [self.posts, self.pages].flatten.each do |page_or_post|
    page_or_post.render(self.layouts, payload)
  end

  self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a } }
  self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a } }
rescue Errno::ENOENT => e
  # ignore missing layout dir
end
reset() click to toggle source

Reset Site details.

Returns nothing

# File lib/jekyll/site.rb, line 47
def reset
  self.time            = if self.config['time']
                           Time.parse(self.config['time'].to_s)
                         else
                           Time.now
                         end
  self.layouts         = {}
  self.posts           = []
  self.pages           = []
  self.static_files    = []
  self.categories      = Hash.new { |hash, key| hash[key] = [] }
  self.tags            = Hash.new { |hash, key| hash[key] = [] }
  self.data            = {}
  self.data_sources    = {}

  if self.limit_posts < 0
    raise ArgumentError, "limit_posts must be a non-negative number"
  end
end
setup() click to toggle source

Load necessary libraries, plugins, converters, and generators.

Returns nothing.

# File lib/jekyll/site.rb, line 70
def setup
  ensure_not_in_dest

  # If safe mode is off, load in any Ruby files under the plugins
  # directory.
  unless self.safe
    self.plugins.each do |plugins|
        Dir[File.join(plugins, "**/*.rb")].each do |f|
          require f
        end
    end
  end

  self.converters = instantiate_subclasses(Jekyll::Converter)
  self.generators = instantiate_subclasses(Jekyll::Generator)
end
site_data() click to toggle source

Prepare site data for site payload. The method maintains backward compatibility if the key ‘data’ is already used in _config.yml.

Returns the Hash to be hooked to site.data.

# File lib/jekyll/site.rb, line 306
def site_data
  self.config['data'] || self.data
end
site_payload() click to toggle source

The Hash payload containing site-wide data.

Returns the Hash: { “site” => data } where data is a Hash with keys:

"time"       - The Time as specified in the configuration or the
               current time if none was specified.
"posts"      - The Array of Posts, sorted chronologically by post date
               and then title.
"pages"      - The Array of all Pages.
"html_pages" - The Array of HTML Pages.
"categories" - The Hash of category values and Posts.
               See Site#post_attr_hash for type info.
"tags"       - The Hash of tag values and Posts.
               See Site#post_attr_hash for type info.
# File lib/jekyll/site.rb, line 323
def site_payload
  {"jekyll" => { "version" => Jekyll::VERSION },
   "site" => self.data_sources.merge(self.config).merge({
      "time"       => self.time,
      "posts"      => self.posts.sort { |a, b| b <=> a },
      "pages"      => self.pages,
      "html_pages" => self.pages.reject { |page| !page.html? },
      "categories" => post_attr_hash('categories'),
      "tags"       => post_attr_hash('tags'),
      "data"       => site_data})}
end
write() click to toggle source

Write static files, pages, and posts.

Returns nothing.

# File lib/jekyll/site.rb, line 276
def write
  each_site_file { |item| item.write(self.dest) }
end

Private Instance Methods

has_relative_page?() click to toggle source
# File lib/jekyll/site.rb, line 429
def has_relative_page?
  self.pages.any? { |page| page.uses_relative_permalinks }
end
has_yaml_header?(file) click to toggle source
# File lib/jekyll/site.rb, line 433
def has_yaml_header?(file)
  "---" == File.open(file) { |fd| fd.read(3) }
end
limit_posts!() click to toggle source
# File lib/jekyll/site.rb, line 437
def limit_posts!
  limit = self.posts.length < limit_posts ? self.posts.length : limit_posts
  self.posts = self.posts[-limit, limit]
end
sanitize_filename(name) click to toggle source
# File lib/jekyll/site.rb, line 446
def sanitize_filename(name)
  name = name.gsub(/[^\w\s_-]+/, '')
  name = name.gsub(/(^|\b\s)\s+($|\s?\b)/, '\\1\\2')
  name = name.gsub(/\s+/, '_')
end
site_cleaner() click to toggle source
# File lib/jekyll/site.rb, line 442
def site_cleaner
  @site_cleaner ||= Cleaner.new(self)
end