Class: Plate::Builder

Inherits:
Object
  • Object
show all
Includes:
Callbacks
Defined in:
lib/plate/builder.rb

Overview

The builder is used to compile create a site from a source directory and output it to a destination.

In most cases, the Builder is called directly from the command line tools (see CLI) and does not need to be called directly.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Callbacks

included

Constructor Details

#initialize(source, destination, options = {}) ⇒ Builder

Create a new instance of the builder for the given site source, destination and options.

In most cases this should be initialized from the command line utilities.



37
38
39
40
41
42
43
# File 'lib/plate/builder.rb', line 37

def initialize(source, destination, options = {})
  @source = source
  @destination = destination
  @metadata = {}
  @options = Hash === options ? options.clone : {}
  @options.symbolize_keys!
end

Instance Attribute Details

#destinationString

Returns The destination directory path where the site should be placed upon a completed build.

Returns:

  • (String)

    The destination directory path where the site should be placed upon a completed build.



13
14
15
# File 'lib/plate/builder.rb', line 13

def destination
  @destination
end

#enable_loggingBoolean

Returns Is logging enabled for this build? Set using the ‘–verbose` command line option.

Returns:

  • (Boolean)

    Is logging enabled for this build? Set using the ‘–verbose` command line option.



16
17
18
# File 'lib/plate/builder.rb', line 16

def enable_logging
  @enable_logging
end

#helpersArray (readonly)

Returns A list of helper classes loaded from the ‘source/helpers` directory.

Returns:

  • (Array)

    A list of helper classes loaded from the ‘source/helpers` directory.



31
32
33
# File 'lib/plate/builder.rb', line 31

def helpers
  @helpers
end

#metadataHash

Returns A hash of meta values loaded from the config file in the site’s source.

Returns:

  • (Hash)

    A hash of meta values loaded from the config file in the site’s source.



19
20
21
# File 'lib/plate/builder.rb', line 19

def 
  @metadata
end

#optionsHash

Returns The options hash for this site build.

Returns:

  • (Hash)

    The options hash for this site build.



22
23
24
# File 'lib/plate/builder.rb', line 22

def options
  @options
end

#siteSite

Returns The site instance for this build.

Returns:

  • (Site)

    The site instance for this build.



25
26
27
# File 'lib/plate/builder.rb', line 25

def site
  @site
end

#sourceString

Returns The source directory path where the site’s content is loaded from.

Returns:

  • (String)

    The source directory path where the site’s content is loaded from.



28
29
30
# File 'lib/plate/builder.rb', line 28

def source
  @source
end

Instance Method Details

#cache_locationString

The directory where the build details are cached. Caching is used to store temporary data, and as a temporary spot to build the site in before it is moved to the destination directory.

Caching is probably a bad name for this since nothing is truly “cached”, it is merely a temporary directory.

The directory can be set in a site options, or uses the default which is in the user’s current home directory under ~/.plate…

Returns:

  • (String)


56
57
58
59
60
61
62
63
64
# File 'lib/plate/builder.rb', line 56

def cache_location
  return @cache_location if @cache_location

  if self.options.has_key?(:cache_location)
    @cache_location ||= File.expand_path(self.options[:cache_location])
  else
    @cache_location ||= File.expand_path("~/.plate/#{self.id}")
  end
end

#clear_cache!Object

Remove any caches and temporary data from this site build.



67
68
69
70
71
72
73
# File 'lib/plate/builder.rb', line 67

def clear_cache!
  FileUtils.rm_rf(cache_location)

  @cache_location = nil
  @tmp_destination = nil
  @loaded = false
end

#configHash

Loads the site, if not already loaded and returns the options listed.

Returns:

  • (Hash)


78
79
80
81
# File 'lib/plate/builder.rb', line 78

def config
  load!
  @options
end

#idString

A unique id for this site, based off of the source directory.

Returns:

  • (String)


86
87
88
89
# File 'lib/plate/builder.rb', line 86

def id
  check_source!
  @id ||= [ File.basename(source), Digest::MD5.hexdigest(source) ].collect { |s| s.to_s.downcase.parameterize }.join('-')
end

#items?Boolean

Are there any items loaded within this site build? Returns false if there are no items.

When builing a site from the source directory and there are no items persent, the builder will exit.

Returns:

  • (Boolean)


97
98
99
# File 'lib/plate/builder.rb', line 97

def items?
  self.total_items > 0
end

#load!Boolean

Read the source directory from the file system, configure the Site instance, and load any helpers and plugins.

The loaded data is cached so this method can safely be called multiple times without having to read from the filesystem more than once.

Returns:

  • (Boolean)

    Was the source loaded?



108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/plate/builder.rb', line 108

def load!
  unless @loaded
    log('Site builder initialized.')

    require_plugins!
    load_config_file!
    setup_site!
    setup_tmp_directory!

    @loaded = true
  end

  @loaded
end

#rebuild!Boolean

Rebuilds the entire site from source. Used when watching a directory for changes.

Returns:

  • (Boolean)


133
134
135
136
137
138
139
140
141
142
143
# File 'lib/plate/builder.rb', line 133

def rebuild!
  log('Re-rendering site...')

  clear_cache!
  load!
  site.reload!
  render_site!
  copy_to_destination!

  true
end

#relative_path(file_or_directory) ⇒ String

Utility method to grab the relative path of a specific file from the site’s source.

Returns:

  • (String)

    File path relative to source directory.



126
127
128
# File 'lib/plate/builder.rb', line 126

def relative_path(file_or_directory)
  file_or_directory.gsub(/^#{Regexp.quote(source)}(.*)$/, '\1')
end

#reloadable?(relative_file) ⇒ Boolean

When watching a directory for changes, allow reloading of site content based on modifications only in the content, layouts and posts folder. Changes to config or lib files will need to be reloaded manually.

Returns:

  • (Boolean)


150
151
152
# File 'lib/plate/builder.rb', line 150

def reloadable?(relative_file)
  relative_file =~ /^\/?(assets|content|layouts|posts)\/(.*?)/
end

#render!Boolean

Start the rendering of the site based on the provided, source, destination and config options.

The site will be loaded if it has not already been read from source, and rendered first to the temporary #cache_location

Returns:

  • (Boolean)


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/plate/builder.rb', line 161

def render!
  @start_time = Time.now

  around_callback :render do
    log("Building full site...")

    load!
    render_site!
    copy_to_destination!

    @end_time = Time.now

    log("Site build completed in #{timer} seconds")
  end

  true
end

#render_file!(relative_file_path) ⇒ Boolean

Render a single file from the source to destination directories. This is used when watching a site for changes and recompiling a specific file on demand.

For layout files, the entire site is reloaded. For all other files, only that file and corresponding destination file are reloaded.

This may produce some unexpected behavior due to plugins and helpers not being reloaded and is still considered experimental.

Returns:

  • (Boolean)


189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
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
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/plate/builder.rb', line 189

def render_file!(relative_file_path)
  load!

  page = site.find(relative_file_path)

  # Ensure that the file path it is trying to reload actually exists
  if page and page.file?
    # If the file is a layout, rebuild all pages using it
    if Layout === page
      page.reload!

      log("Building layout [#{page.relative_file}]")

      # Rebuild all pages using that particular layout.
      site.find_by_layout(page.relative_file).each do |layout_page|
        layout_page.layout = page
        self.render_file!(layout_page.relative_file)
      end
    else
      log("Building file [#{page.relative_file}]")

      # Does the file have an existing temporary file in the {#cache_location}
      existing_tmp = File.join(tmp_destination, page.file_path)

      if File.exists?(existing_tmp)
        FileUtils.rm_rf(existing_tmp)
      end

      page.reload!

      case page
      when Asset
      when Draft
        # If this page was a draft, and now is published. Reload the entire site
        # and publish it.
        if page.publish?
          FileUtils.rm_rf(File.join(site.destination, page.file_path))
          self.rebuild! and return
        end
      when StaticPage
        # If this page was static and needs to be upgraded to a regular page, reload the
        # entire site.
        if page.upgrade?
          FileUtils.rm_rf(File.join(site.destination, page.file_path))
          self.rebuild! and return
        end
      else
        # If a page is downgraded from Page to StaticPage, reload site
        if page.downgrade?
          FileUtils.rm_rf(File.dirname(File.join(site.destination, page.file_path)))
          self.rebuild! and return
        end
      end

      page.write!

      # File should exist again, even though we just removed it since we re-wrote it.
      if File.exists?(existing_tmp)
        existing = File.join(destination, page.file_path)

        if File.exists?(existing)
          log("Removing existing file [#{existing}]", :indent)
          FileUtils.rm_rf(existing)
        end

        FileUtils.mkdir_p(File.dirname(existing))
        FileUtils.cp(existing_tmp, existing)

        log("File build complete.", :indent)
      end
    end
  else
    # Check for partials, and run any files that reference it.
    if File.basename(relative_file_path) =~ /^_/
      log("Partial modified. Reloading referencing files", :indent)

      name = Partial.name(site, relative_file_path.gsub(/^\/?(content|assets)\//, ''))
      partial = Partial.find(site, name)

      if partial
        partial.reload!

        site.pages.each do |page|
          if page.partials.include?(name)
            self.render_file!(page.relative_file)
          end
        end
      else
        partial_name = File.basename(relative_file_path, '.*').gsub(/^_/, '')
        other_files = site.find_by_extension(File.extname(relative_file_path))

        other_files.each do |file|
          if Array === file.partials
            if file.partials.include?(partial_name)
              self.render_file!(file.relative_file)
            end
          end
        end
      end
    else
      log("Cannot render file, it doesn't exist. [#{relative_file_path}]")
    end
  end

  true
end

#timerFloat

Returns the time it took to run render! (in milliseconds)

Returns:

  • (Float)

    Milliseconds



308
309
310
311
# File 'lib/plate/builder.rb', line 308

def timer
  return 0 unless @end_time and @start_time
  (@end_time - @start_time).round
end

#tmp_destinationString

The directory path of where to put the files while the site is being built.

If this value is nil, no temporary directory is used and files are built directly in the normal destination folder.

Returns:

  • (String)

    Full file path



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/plate/builder.rb', line 319

def tmp_destination
  return @tmp_destination if @tmp_destination

  result = ""

  if options.has_key?(:tmp_destination)
    if options[:tmp_destination]
      result = File.expand_path(options[:tmp_destination])
    end
  else
    result = File.join(cache_location, 'build-cache')
  end

  @tmp_destination = result
end

#tmp_destination?Boolean

Is this site using a temporary destination location?

Returns:

  • (Boolean)


338
339
340
# File 'lib/plate/builder.rb', line 338

def tmp_destination?
  tmp_destination.to_s.size > 0
end

#total_itemsInteger

The total number of all assets, layouts pages and posts in the source directory.

Returns:

  • (Integer)


300
301
302
303
# File 'lib/plate/builder.rb', line 300

def total_items
  return 0 unless site
  @total_items ||= site.all_files.size
end