Class: Jekyll::Site

Inherits:
Object
  • Object
show all
Defined in:
lib/jekyll/site.rb,
lib/jekyll/cleaner.rb

Defined Under Namespace

Classes: Cleaner

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Site

Public: Initialize a new Site.

config - A Hash containing site configuration details.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 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

Instance Attribute Details

#baseurlObject

Returns the value of attribute baseurl.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def baseurl
  @baseurl
end

#categoriesObject

Returns the value of attribute categories.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def categories
  @categories
end

#configObject

Returns the value of attribute config.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def config
  @config
end

#convertersObject

Returns the value of attribute converters.



8
9
10
# File 'lib/jekyll/site.rb', line 8

def converters
  @converters
end

#dataObject

Returns the value of attribute data.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def data
  @data
end

#data_sourcesObject

Returns the value of attribute data_sources.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def data_sources
  @data_sources
end

#destObject

Returns the value of attribute dest.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def dest
  @dest
end

#excludeObject

Returns the value of attribute exclude.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def exclude
  @exclude
end

#file_read_optsObject

Returns the value of attribute file_read_opts.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def file_read_opts
  @file_read_opts
end

#futureObject

Returns the value of attribute future.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def future
  @future
end

#generatorsObject

Returns the value of attribute generators.



8
9
10
# File 'lib/jekyll/site.rb', line 8

def generators
  @generators
end

#includeObject

Returns the value of attribute include.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def include
  @include
end

#keep_filesObject

Returns the value of attribute keep_files.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def keep_files
  @keep_files
end

#layoutsObject

Returns the value of attribute layouts.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def layouts
  @layouts
end

#limit_postsObject

Returns the value of attribute limit_posts.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def limit_posts
  @limit_posts
end

#lsiObject

Returns the value of attribute lsi.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def lsi
  @lsi
end

#pagesObject

Returns the value of attribute pages.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def pages
  @pages
end

Returns the value of attribute permalink_style.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def permalink_style
  @permalink_style
end

#pluginsObject

Returns the value of attribute plugins.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def plugins
  @plugins
end

#postsObject

Returns the value of attribute posts.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def posts
  @posts
end

#pygmentsObject

Returns the value of attribute pygments.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def pygments
  @pygments
end

#safeObject

Returns the value of attribute safe.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def safe
  @safe
end

#show_draftsObject

Returns the value of attribute show_drafts.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def show_drafts
  @show_drafts
end

#sourceObject

Returns the value of attribute source.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def source
  @source
end

#static_filesObject

Returns the value of attribute static_files.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def static_files
  @static_files
end

#tagsObject

Returns the value of attribute tags.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def tags
  @tags
end

#timeObject

Returns the value of attribute time.



3
4
5
# File 'lib/jekyll/site.rb', line 3

def time
  @time
end

Instance Method Details

#aggregate_post_info(post) ⇒ Object

Aggregate post information

post - The Post object to aggregate information for

Returns nothing



401
402
403
404
405
# File 'lib/jekyll/site.rb', line 401

def (post)
  self.posts << post
  post.categories.each { |c| self.categories[c] << post }
  post.tags.each { |c| self.tags[c] << post }
end

#cleanupObject

Remove orphaned files and empty directories in destination.

Returns nothing.



269
270
271
# File 'lib/jekyll/site.rb', line 269

def cleanup
  site_cleaner.cleanup!
end

#each_site_fileObject



419
420
421
422
423
424
425
# 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_destObject

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



89
90
91
92
93
94
95
96
# 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) ⇒ Object

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.



343
344
345
346
347
348
349
350
351
352
# 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

#generateObject

Run each of the Generators.

Returns nothing.



243
244
245
246
247
# File 'lib/jekyll/site.rb', line 243

def generate
  self.generators.each do |generator|
    generator.generate(self)
  end
end

#get_entries(dir, subfolder) ⇒ Object

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



389
390
391
392
393
394
# 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

#getConverterImpl(klass) ⇒ Object

Get the implementation class for the given Converter.

klass - The Class of the Converter to fetch.

Returns the Converter instance implementing the given Converter.



359
360
361
362
363
364
365
366
# 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

#instantiate_subclasses(klass) ⇒ Object

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



375
376
377
378
379
380
381
# 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_sourcesObject

Load external data sources to @data_sources

Returns nothing



226
227
228
229
230
231
232
233
234
235
236
237
238
# 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_pathObject

Internal: Setup the plugin search path

Returns an Array of plugin search paths



101
102
103
104
105
106
107
# 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) ⇒ Object

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.


293
294
295
296
297
298
299
300
# 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

#processObject

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

Returns nothing.



35
36
37
38
39
40
41
42
# File 'lib/jekyll/site.rb', line 35

def process
  self.reset
  self.read
  self.generate
  self.render
  self.cleanup
  self.write
end

#readObject

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

Returns nothing.



112
113
114
115
116
117
# 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) ⇒ Object

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

Returns nothing



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# 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 = '') ⇒ Object

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.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# 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) ⇒ Object

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.



191
192
193
194
195
196
197
198
199
200
201
202
# 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)

      (draft)
    end
  end
end

#read_layoutsObject

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

Returns nothing.



123
124
125
126
127
128
129
130
131
132
133
# 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) ⇒ Object

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.



170
171
172
173
174
175
176
177
178
179
180
181
182
183
# 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)
        (post)
      end
    end
  end
end


407
408
409
410
411
412
413
414
415
416
417
# File 'lib/jekyll/site.rb', line 407

def relative_permalinks_deprecation_method
  if config['relative_permalinks'] && has_relative_page?
    $stderr.puts # Places newline after "Generating..."
    Jekyll.logger.warn "Deprecation:", "Starting in 1.1, permalinks for pages" +
                                        " in subfolders must be relative to the" +
                                        " site source directory, not the parent" +
                                        " directory. Check http://jekyllrb.com/docs/upgrading/"+
                                        " for more info."
    $stderr.print Jekyll.logger.formatted_topic("") + "..." # for "done."
  end
end

#renderObject

Render the site to the destination.

Returns nothing.



252
253
254
255
256
257
258
259
260
261
262
263
264
# 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

#resetObject

Reset Site details.

Returns nothing



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 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

#setupObject

Load necessary libraries, plugins, converters, and generators.

Returns nothing.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# 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_dataObject

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.



306
307
308
# File 'lib/jekyll/site.rb', line 306

def site_data
  self.config['data'] || self.data
end

#site_payloadObject

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.


323
324
325
326
327
328
329
330
331
332
333
# 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

#writeObject

Write static files, pages, and posts.

Returns nothing.



276
277
278
# File 'lib/jekyll/site.rb', line 276

def write
  each_site_file { |item| item.write(self.dest) }
end