Skip to content

Instantly share code, notes, and snippets.

@imathis
Last active December 19, 2015 11:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imathis/5946651 to your computer and use it in GitHub Desktop.
Save imathis/5946651 to your computer and use it in GitHub Desktop.
Guard-Jekyll-Plus is a fancy Guard script for managing "smart" Jekyll builds. Changes in the source directory to non-template files will trigger a simple filesystem copy (or delete) to the destination directory. Changes to template files (configured by file extension) will trigger a Jekyll build.
require 'guard'
require 'guard/guard'
require 'jekyll'
module Guard
class Jekyll < Guard
def initialize (watchers=[], options={})
super
@options = {
:extensions => [],
:config => '_config.yml'
}.merge(options)
default_extensions = ['md','markdown','textile','html','haml','slim','xml']
config = ::Jekyll.configuration(options)
@site = ::Jekyll::Site.new config
@options[:source] = config['source']
@options[:destination] = config['destination']
@options[:extensions] = @options[:extensions].concat(default_extensions).flatten.uniq
# Convert array of extensions into a regex for matching file extensions eg, /\.md$|\.markdown$|\.html$/i
@extensions = Regexp.new @options[:extensions].map { |e| (e << '$').gsub('\.', '\\.') }.join('|'), true
end
# Calls #run_all if the :all_on_start option is present.
def start
UI.info 'Guard::Jekyll is watching for file changes'
rebuild
end
def reload
compile
end
def run_all
rebuild
end
def run_on_changes(paths)
matches = []
copy_files = []
remove_files = []
paths.each do |file|
if File.exist? file
if file =~ @extensions or file !=~ /^#{@options[:source]}/
matches.push file
else
copy_files.push file
end
else
remove_files.push file
end
end
if matches.length > 0
rebuild
else
# If changes don't trigger Jekyll extension matches
# manually copy and remove changed files
copy_files.each { |f| copy f }
remove_files.each { |f| remove f }
end
end
private
def destination_path(file)
file.sub /^#{@options[:source]}/, "#{@options[:destination]}"
end
def copy(file)
destination_file = destination_path file
FileUtils.mkdir_p File.dirname(destination_file)
FileUtils.cp file, destination_file
UI.info "Guard::Jekyll" + " copied ".yellow + "#{file} -> #{destination_file}"
true
end
def remove(file)
destination_file = destination_path file
if File.exist? destination_file
begin
# Remove deleted source file from destination
FileUtils.rm destination_file
UI.info "Guard::Jekyll" + " delete ".red + destination_file
# Remove empty directories from destination
dir = File.dirname destination_file
if Dir[dir+'/*'].empty?
FileUtils.rm_r(dir)
UI.info "Guard::Jekyll" + " delete ".red + dir
end
rescue Exception => e
UI.error "Guard::Jekyll" + " failed ".red + e
throw :task_has_failed
end
end
true
end
def rebuild
UI.info "Guard::Jekyll "+" building".yellow
@site.process
UI.info "Guard::Jekyll "+" complete".green + " site built in #{@options[:destination]}/"
rescue Exception => e
UI.error "Guard::Jekyll failed"
throw :task_has_failed
end
end
end
require 'guards/guard-jekyll-plus.rb'
# Sample guard
guard :jekyll do
watch /^source/
watch '_config.yml'
end
@parkr
Copy link

parkr commented Jul 8, 2013

If you want to handle multiple config files, convert your :config option to an array

@options = {
  :extensions => [], 
  :config => ['_config.yml']
}.merge(options)

(If it can be a string and not a symbol, all the better)

Then convert it for Jekyll:

options["config"] = options.delete(:config)
Jekyll.configuration(options)

And that should work! You should see (in your console output) that all of the files were read in properly. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment