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 gems].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

#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

#gemsObject

Returns the value of attribute gems.



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

def gems
  @gems
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



376
377
378
379
380
# File 'lib/jekyll/site.rb', line 376

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.



251
252
253
# File 'lib/jekyll/site.rb', line 251

def cleanup
  site_cleaner.cleanup!
end

#each_site_fileObject



394
395
396
397
398
399
400
# File 'lib/jekyll/site.rb', line 394

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.



91
92
93
94
95
96
97
98
# File 'lib/jekyll/site.rb', line 91

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.



325
326
327
# File 'lib/jekyll/site.rb', line 325

def filter_entries(entries)
  EntryFilter.new(self).filter(entries)
end

#generateObject

Run each of the Generators.

Returns nothing.



225
226
227
228
229
# File 'lib/jekyll/site.rb', line 225

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



364
365
366
367
368
369
# File 'lib/jekyll/site.rb', line 364

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.



334
335
336
337
338
339
340
341
# File 'lib/jekyll/site.rb', line 334

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



350
351
352
353
354
355
356
# File 'lib/jekyll/site.rb', line 350

def instantiate_subclasses(klass)
  klass.subclasses.select do |c|
    !self.safe || c.safe
  end.sort.map do |c|
    c.new(self.config)
  end
end

#plugins_pathObject

Internal: Setup the plugin search path

Returns an Array of plugin search paths



103
104
105
106
107
108
109
# File 'lib/jekyll/site.rb', line 103

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.


275
276
277
278
279
280
281
282
# File 'lib/jekyll/site.rb', line 275

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.



114
115
116
117
118
# File 'lib/jekyll/site.rb', line 114

def read
  self.read_layouts
  self.read_directories
  self.read_data(config['data_source'])
end

#read_data(dir) ⇒ Object

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

Returns nothing



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/jekyll/site.rb', line 206

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.



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/jekyll/site.rb', line 143

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.



187
188
189
190
191
192
193
# File 'lib/jekyll/site.rb', line 187

def read_drafts(dir)
  drafts = read_things(dir, '_drafts', Draft)

  drafts.each do |draft|
    (draft)
  end
end

#read_layoutsObject

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

Returns nothing.



124
125
126
127
128
129
130
131
132
133
134
# File 'lib/jekyll/site.rb', line 124

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.



171
172
173
174
175
176
177
178
179
# File 'lib/jekyll/site.rb', line 171

def read_posts(dir)
   posts = read_things(dir, '_posts', Post)

   posts.each do |post|
     if post.published && (self.future || post.date <= self.time)
       (post)
     end
   end
end

#read_things(dir, magic_dir, klass) ⇒ Object



195
196
197
198
199
200
201
# File 'lib/jekyll/site.rb', line 195

def read_things(dir, magic_dir, klass)
  get_entries(dir, magic_dir).map do |entry|
    klass.new(self, self.source, dir, entry) if klass.valid?(entry)
  end.reject do |entry|
    entry.nil?
  end
end


382
383
384
385
386
387
388
389
390
391
392
# File 'lib/jekyll/site.rb', line 382

def relative_permalinks_deprecation_method
  if config['relative_permalinks'] && has_relative_page?
    $stderr.puts # Places newline after "Generating..."
    Jekyll.logger.warn "Deprecation:", "Starting in 2.0, 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.



234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/jekyll/site.rb', line 234

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
# 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            = {}

  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.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/jekyll/site.rb', line 69

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")].sort.each do |f|
          require f
        end
    end
    self.gems.each do |gem|
      require gem
    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.



288
289
290
# File 'lib/jekyll/site.rb', line 288

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.


305
306
307
308
309
310
311
312
313
314
315
# File 'lib/jekyll/site.rb', line 305

def site_payload
  {"jekyll" => { "version" => Jekyll::VERSION },
   "site" => 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.



258
259
260
# File 'lib/jekyll/site.rb', line 258

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