aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/blockquote.rb74
-rw-r--r--plugins/category_generator.rb163
-rw-r--r--plugins/code_block.rb80
-rw-r--r--plugins/compass_compiler.rb1
-rw-r--r--plugins/custom_filters.rb75
-rw-r--r--plugins/figure_tag.rb69
-rw-r--r--plugins/gist_tag.rb94
-rw-r--r--plugins/haml.rb24
-rw-r--r--plugins/include_code.rb55
-rw-r--r--plugins/pullquote.rb40
-rw-r--r--plugins/pygments_cache_patch.rb30
-rw-r--r--plugins/render_partial.rb52
-rw-r--r--plugins/sitemap_generator.rb308
-rw-r--r--plugins/titlecase.rb36
14 files changed, 1101 insertions, 0 deletions
diff --git a/plugins/blockquote.rb b/plugins/blockquote.rb
new file mode 100644
index 00000000..d292ce8e
--- /dev/null
+++ b/plugins/blockquote.rb
@@ -0,0 +1,74 @@
+#
+# Author: Brandon Mathis
+# A full rewrite based on the work of: Josediaz Gonzalez - https://github.com/josegonzalez/josediazgonzalez.com/blob/master/_plugins/blockquote.rb
+#
+# Outputs a string with a given attribution as a quote
+#
+# {% blockquote Bobby Willis http://google.com/search?q=pants the search for bobby's pants %}
+# Wheeee!
+# {% endblockquote %}
+# ...
+# <blockquote>
+# <p>Wheeee!</p>
+# <footer>
+# <strong>Bobby Willis</strong><cite><a href="http://google.com/search?q=pants">The Search For Bobby's Pants</a>
+# </blockquote>
+#
+require './plugins/titlecase.rb'
+
+module Jekyll
+
+ class Blockquote < Liquid::Block
+ FullCiteWithTitle = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)\s+(.+)/i
+ FullCite = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)/i
+ Author = /(\S[\S\s]*)/
+
+ def initialize(tag_name, markup, tokens)
+ @by = nil
+ @source = nil
+ @title = nil
+ if markup =~ FullCiteWithTitle
+ @by = $1
+ @source = $2 + $3
+ @title = $4.titlecase
+ elsif markup =~ FullCite
+ @by = $1
+ @source = $2 + $3
+ elsif markup =~ Author
+ @by = $1
+ end
+ super
+ end
+
+ def render(context)
+ output = paragraphize(super.map(&:strip).join)
+ author = "<strong>#{@by.strip}</strong>"
+ if @source
+ url = @source.match(/https?:\/\/(.+)/)[1].split('/')
+ parts = []
+ url.each do |part|
+ if (parts + [part]).join('/').length < 32
+ parts << part
+ end
+ end
+ source = parts.join('/')
+ source << '/&hellip;' unless source == @source
+ end
+ cite = "<cite><a href='#{@source}'>#{(@title || source)}</a></cite>"
+ result = if @by.nil?
+ output
+ elsif !@source.nil?
+ "#{output}<footer>#{author + cite}</footer>"
+ else
+ "#{output}<footer>#{author}</footer>"
+ end
+ "<blockquote>#{result}</blockquote>"
+ end
+
+ def paragraphize(input)
+ "<p>#{input.gsub(/\n\n/, '</p><p>').gsub(/\n/, '<br/>')}</p>"
+ end
+ end
+end
+
+Liquid::Template.register_tag('blockquote', Jekyll::Blockquote)
diff --git a/plugins/category_generator.rb b/plugins/category_generator.rb
new file mode 100644
index 00000000..c2e9a46e
--- /dev/null
+++ b/plugins/category_generator.rb
@@ -0,0 +1,163 @@
+# Jekyll category page generator.
+# http://recursive-design.com/projects/jekyll-plugins/
+#
+# Version: 0.1.4 (201101061053)
+#
+# Copyright (c) 2010 Dave Perrett, http://recursive-design.com/
+# Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
+#
+# A generator that creates category pages for jekyll sites.
+#
+# To use it, simply drop this script into the _plugins directory of your Jekyll site. You should
+# also create a file called 'category_index.html' in the _layouts directory of your jekyll site
+# with the following contents (note: you should remove the leading '# ' characters):
+#
+# ================================== COPY BELOW THIS LINE ==================================
+# ---
+# layout: default
+# ---
+#
+# <h1 class="category">{{ page.title }}</h1>
+# <ul class="posts">
+# {% for post in site.categories[page.category] %}
+# <div>{{ post.date | date_to_html_string }}</div>
+# <h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
+# <div class="categories">Filed under {{ post.categories | category_links }}</div>
+# {% endfor %}
+# </ul>
+# ================================== COPY ABOVE THIS LINE ==================================
+#
+# You can alter the _layout_ setting if you wish to use an alternate layout, and obviously you
+# can change the HTML above as you see fit.
+#
+# When you compile your jekyll site, this plugin will loop through the list of categories in your
+# site, and use the layout above to generate a page for each one with a list of links to the
+# individual posts.
+#
+# Included filters :
+# - category_links: Outputs the list of categories as comma-separated <a> links.
+# - date_to_html_string: Outputs the post.date as formatted html, with hooks for CSS styling.
+#
+# Available _config.yml settings :
+# - category_dir: The subfolder to build category pages in (default is 'categories').
+# - category_title_prefix: The string used before the category name in the page title (default is
+# 'Category: ').
+module Jekyll
+
+
+ # The CategoryIndex class creates a single category page for the specified category.
+ class CategoryIndex < Page
+
+ # Initializes a new CategoryIndex.
+ #
+ # +base+ is the String path to the <source>.
+ # +category_dir+ is the String path between <source> and the category folder.
+ # +category+ is the category currently being processed.
+ def initialize(site, base, category_dir, category)
+ @site = site
+ @base = base
+ @dir = category_dir
+ @name = 'index.html'
+ self.process(@name)
+ # Read the YAML data from the layout page.
+ self.read_yaml(File.join(base, '_layouts'), 'category_index.html')
+ self.data['category'] = category
+ # Set the title for this page.
+ title_prefix = site.config['category_title_prefix'] || 'Category: '
+ self.data['title'] = "#{title_prefix}#{category}"
+ # Set the meta-description for this page.
+ meta_description_prefix = site.config['category_meta_description_prefix'] || 'Category: '
+ self.data['description'] = "#{meta_description_prefix}#{category}"
+ end
+
+ end
+
+
+ # The Site class is a built-in Jekyll class with access to global site config information.
+ class Site
+
+ # Creates an instance of CategoryIndex for each category page, renders it, and
+ # writes the output to a file.
+ #
+ # +category_dir+ is the String path to the category folder.
+ # +category+ is the category currently being processed.
+ def write_category_index(category_dir, category)
+ index = CategoryIndex.new(self, self.source, category_dir, category)
+ index.render(self.layouts, site_payload)
+ index.write(self.dest)
+ # Record the fact that this page has been added, otherwise Site::cleanup will remove it.
+ self.pages << index
+ end
+
+ # Loops through the list of category pages and processes each one.
+ def write_category_indexes
+ if self.layouts.key? 'category_index'
+ dir = self.config['category_dir'] || 'categories'
+ self.categories.keys.each do |category|
+ self.write_category_index(File.join(dir, category.gsub(/_|\W/, '-')), category)
+ end
+
+ # Throw an exception if the layout couldn't be found.
+ else
+ throw "No 'category_index' layout found."
+ end
+ end
+
+ end
+
+
+ # Jekyll hook - the generate method is called by jekyll, and generates all of the category pages.
+ class GenerateCategories < Generator
+ safe true
+ priority :low
+
+ def generate(site)
+ site.write_category_indexes
+ end
+
+ end
+
+
+ # Adds some extra filters used during the category creation process.
+ module Filters
+
+ # Outputs a list of categories as comma-separated <a> links. This is used
+ # to output the category list for each post on a category page.
+ #
+ # +categories+ is the list of categories to format.
+ #
+ # Returns string
+ #
+ def category_links(categories)
+ dir = @context.registers[:site].config['category_dir']
+ root_url = @context.registers[:site].config['root']
+ categories = categories.sort!.map do |item|
+ "<a class='category' href='#{root_url}/#{dir}/#{item.gsub(/_|\W/, '-')}/'>#{item}</a>"
+ end
+
+ case categories.length
+ when 0
+ ""
+ when 1
+ categories[0].to_s
+ else
+ "#{categories[0...-1].join(', ')}, #{categories[-1]}"
+ end
+ end
+
+ # Outputs the post.date as formatted html, with hooks for CSS styling.
+ #
+ # +date+ is the date object to format as HTML.
+ #
+ # Returns string
+ def date_to_html_string(date)
+ result = '<span class="month">' + date.strftime('%b').upcase + '</span> '
+ result += date.strftime('<span class="day">%d</span> ')
+ result += date.strftime('<span class="year">%Y</span> ')
+ result
+ end
+
+ end
+
+end
+
diff --git a/plugins/code_block.rb b/plugins/code_block.rb
new file mode 100644
index 00000000..00762d8a
--- /dev/null
+++ b/plugins/code_block.rb
@@ -0,0 +1,80 @@
+# Title: Simple Code Blocks for Jekyll
+# Author: Brandon Mathis http://brandonmathis.com
+# Description: Write codeblocks with semantic HTML5 <figure> and <figcaption> elements and optional syntax highlighting — all with a simple, intuitive interface.
+#
+# Syntax: {% codeblock [title] [url] [link text] %}
+#
+# For syntax highlighting, put a file extension somewhere in the title. examples:
+# {% codeblock file.sh %}
+# {% codeblock Time to be Awesome! (awesome.rb) %}
+#
+# Example:
+#
+# {% codeblock Got pain? painreleif.sh http://site.com/painreleief.sh Download it! %}
+# $ rm -rf ~/PAIN
+# {% endcodeblock %}
+#
+# Output:
+#
+# <figure role=code>
+# <figcaption><span>Got pain? painrelief.sh</span> <a href="http://site.com/painrelief.sh">Download it!</a>
+# <div class="highlight"><pre><code class="sh">
+# -- nicely escaped highlighted code --
+# </code></pre></div>
+# </figure>
+#
+# Example 2 (no syntax highlighting):
+#
+# {% codeblock %}
+# <sarcasm>Ooooh, sarcasm... How original!</sarcasm>
+# {% endcodeblock %}
+#
+# <figure role=code>
+# <pre><code>&lt;sarcasm> Ooooh, sarcasm... How original!&lt;/sarcasm></code></pre>
+# </figure>
+#
+module Jekyll
+
+ class CodeBlock < Liquid::Block
+ CaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)\s+(.+)/i
+ CaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)/i
+ Caption = /(\S[\S\s]*)/
+ def initialize(tag_name, markup, tokens)
+ @title = nil
+ @caption = nil
+ @highlight = true
+ if markup =~ CaptionUrlTitle
+ @file = $1
+ @caption = "<figcaption><span>#{$1}</span><a href='#{$2 + $3}'>#{$4}</a</figcaption>"
+ elsif markup =~ CaptionUrl
+ @file = $1
+ @caption = "<figcaption><span>#{$1}</span><a href='#{$2 + $3}'>link</a</figcaption>"
+ elsif markup =~ Caption
+ @file = $1
+ @caption = "<figcaption><span>#{$1}</span></figcaption>\n"
+ end
+ if @file =~ /\S[\S\s]*\.(\w+)/
+ @filetype = $1
+ end
+ super
+ end
+
+ def render(context)
+ output = super
+ code = super.join
+ source = "<figure role=code>\n"
+ source += @caption if @caption
+ if @filetype
+ source += "{% highlight #{@filetype} %}\n" + code + "\n{% endhighlight %}\n</figure>"
+ else
+ source += "<pre><code>" + code.gsub!(/</,'&lt;') + "</code></pre>\n</figure>"
+ end
+ partial = Liquid::Template.parse(source)
+ context.stack do
+ partial.render(context)
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('codeblock', Jekyll::CodeBlock)
diff --git a/plugins/compass_compiler.rb b/plugins/compass_compiler.rb
new file mode 100644
index 00000000..dcec746a
--- /dev/null
+++ b/plugins/compass_compiler.rb
@@ -0,0 +1 @@
+system "compass compile --css-dir source/stylesheets"
diff --git a/plugins/custom_filters.rb b/plugins/custom_filters.rb
new file mode 100644
index 00000000..f0db30ee
--- /dev/null
+++ b/plugins/custom_filters.rb
@@ -0,0 +1,75 @@
+#custom filters for Octopress
+
+module OctopressFilters
+ # Used on the blog index to split posts on the <!--more--> marker
+ def exerpt(input)
+ if input.index(/<!--\s*more\s*-->/i)
+ input.split(/<!--\s*more\s*-->/i)[0]
+ else
+ input
+ end
+ end
+
+ # Summary is used on the Archive pages to return the first block of content from a post.
+ def summary(input)
+ if input.index(/\n\n/)
+ input.split(/\n\n/)[0]
+ else
+ input
+ end
+ end
+
+ # Replaces relative urls with full urls
+ def full_urls(input, url='')
+ input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]+)/ do
+ $1+url+$3
+ end
+ end
+
+ # Returns a url without the http:// for use in as a search modifier eg. 'search terms site:website.com'
+ def search_url(input)
+ input.gsub /(https?:\/\/)(\S+)/ do
+ $2
+ end
+ end
+
+ # replaces primes with smartquotes using RubyPants
+ def smart_quotes(input)
+ require 'rubypants'
+ RubyPants.new(input).to_html
+ end
+
+ # Returns a title cased string based on John Gruber's title case http://daringfireball.net/2008/08/title_case_update
+ def titlecase(input)
+ input.titlecase
+ end
+
+ # Returns a datetime if the input is a string
+ def datetime(date)
+ if date.class == String
+ date = Time.parse(date)
+ end
+ date
+ end
+
+ # Returns an ordidinal date eg July 22 2007 -> July 22nd 2007
+ def ordinalize(date)
+ date = datetime(date)
+ "#{date.strftime('%b')} #{ordinal(date.strftime('%e').to_i)}, #{date.strftime('%Y')}"
+ end
+
+ # Returns an ordinal number. 13 -> 13th, 21 -> 21st etc.
+ def ordinal(number)
+ if (11..13).include?(number.to_i % 100)
+ "#{number}<span>th</span>"
+ else
+ case number.to_i % 10
+ when 1; "#{number}<span>st</span>"
+ when 2; "#{number}<span>nd</span>"
+ when 3; "#{number}<span>rd</span>"
+ else "#{number}<span>th</span>"
+ end
+ end
+ end
+end
+Liquid::Template.register_filter OctopressFilters
diff --git a/plugins/figure_tag.rb b/plugins/figure_tag.rb
new file mode 100644
index 00000000..550e677f
--- /dev/null
+++ b/plugins/figure_tag.rb
@@ -0,0 +1,69 @@
+# Title: Simple Image Figure tag for Jekyll
+# Author: Brandon Mathis http://brandonmathis.com
+# Description: Easily output images in <figure> with an optional <figcaption> and class names.
+#
+# Syntax {% figure [class name(s)] url [caption text] %}
+#
+# Example:
+# {% figure left half http://site.com/images/ninja.png Ninja Attack! %}
+#
+# Output:
+# <figure class='left half'><img src="http://site.com/images/ninja.png"><figcaption>Ninja Attack!</figcaption></figure>
+#
+# Example 2 (image with caption)
+# {% figure /images/ninja.png Ninja Attack! %}
+#
+# Output:
+# <figure><img src="/images/ninja.png"><figcaption>Ninja Attack!</figcaption></figure>
+#
+# Example 3 (just an image with classes)
+# {% figure right /images/ninja.png %}
+#
+# Output:
+# <figure><img class="right" src="/images/ninja.png"></figure>
+#
+
+module Jekyll
+
+ class FigureImageTag < Liquid::Tag
+ ClassImgCaption = /(\S[\S\s]*)\s+(https?:\/\/|\/)(\S+)\s+(.+)/i
+ ClassImg = /(\S[\S\s]*)\s+(https?:\/\/|\/)(\S+)/i
+ ImgCaption = /^\s*(https?:\/\/|\/)(\S+)\s+(.+)/i
+ Img = /^\s*(https?:\/\/|\/)(\S+\s)/i
+
+ @img = nil
+ @caption = nil
+ @class = ''
+
+ def initialize(tag_name, markup, tokens)
+ if markup =~ ClassImgCaption
+ @class = $1
+ @img = $2 + $3
+ @caption = $4
+ elsif markup =~ ClassImg
+ @class = $1
+ @img = $2 + $3
+ elsif markup =~ ImgCaption
+ @img = $1 + $2
+ @caption = $3
+ elsif markup =~ Img
+ @img = $1 + $2
+ end
+ super
+ end
+
+ def render(context)
+ output = super
+ if @img
+ figure = "<figure class='#{@class}'>"
+ figure += "<img src='#{@img}'>"
+ figure += "<figcaption>#{@caption}</figcaption>" if @caption
+ figure += "</figure>"
+ else
+ "Error processing input, expected syntax: {% figure [class name(s)] /url/to/image [caption] %}"
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('figure', Jekyll::FigureImageTag)
diff --git a/plugins/gist_tag.rb b/plugins/gist_tag.rb
new file mode 100644
index 00000000..0a8797f8
--- /dev/null
+++ b/plugins/gist_tag.rb
@@ -0,0 +1,94 @@
+# A Liquid tag for Jekyll sites that allows embedding Gists and showing code for non-JavaScript enabled browsers and readers.
+# by: Brandon Tilly
+# Source URL: https://gist.github.com/1027674
+# Post http://brandontilley.com/2011/01/31/gist-tag-for-jekyll.html
+#
+# Example usage: {% gist 1027674 gist_tag.rb %} //embeds a gist for this plugin
+
+require 'cgi'
+require 'digest/md5'
+require 'net/https'
+require 'uri'
+
+module Jekyll
+ class GistTag < Liquid::Tag
+ def initialize(tag_name, text, token)
+ super
+ @text = text
+ @cache_disabled = false
+ @cache_folder = File.expand_path "../_gist_cache", File.dirname(__FILE__)
+ FileUtils.mkdir_p @cache_folder
+ end
+
+ def render(context)
+ if parts = @text.match(/([\d]*) (.*)/)
+ gist, file = parts[1].strip, parts[2].strip
+ script_url = script_url_for gist, file
+ code = get_cached_gist(gist, file) || get_gist_from_web(gist, file)
+ html_output_for script_url, code
+ else
+ ""
+ end
+ end
+
+ def html_output_for(script_url, code)
+ code = CGI.escapeHTML code
+ <<-HTML
+<script src='#{script_url}'></script>
+<noscript><pre><code>#{code}</code></pre></noscript>
+ HTML
+ end
+
+ def script_url_for(gist_id, filename)
+ "https://gist.github.com/#{gist_id}.js?file=#{filename}"
+ end
+
+ def get_gist_url_for(gist, file)
+ "https://raw.github.com/gist/#{gist}/#{file}"
+ end
+
+ def cache(gist, file, data)
+ cache_file = get_cache_file_for gist, file
+ File.open(cache_file, "w") do |io|
+ io.write data
+ end
+ end
+
+ def get_cached_gist(gist, file)
+ return nil if @cache_disabled
+ cache_file = get_cache_file_for gist, file
+ File.read cache_file if File.exist? cache_file
+ end
+
+ def get_cache_file_for(gist, file)
+ bad_chars = /[^a-zA-Z0-9\-_.]/
+ gist = gist.gsub bad_chars, ''
+ file = file.gsub bad_chars, ''
+ md5 = Digest::MD5.hexdigest "#{gist}-#{file}"
+ File.join @cache_folder, "#{gist}-#{file}-#{md5}.cache"
+ end
+
+ def get_gist_from_web(gist, file)
+ gist_url = get_gist_url_for gist, file
+ raw_uri = URI.parse gist_url
+ https = Net::HTTP.new raw_uri.host, raw_uri.port
+ https.use_ssl = true
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ request = Net::HTTP::Get.new raw_uri.request_uri
+ data = https.request request
+ data = data.body
+ cache gist, file, data unless @cache_disabled
+ data
+ end
+ end
+
+ class GistTagNoCache < GistTag
+ def initialize(tag_name, text, token)
+ super
+ @cache_disabled = true
+ end
+ end
+end
+
+Liquid::Template.register_tag('gist', Jekyll::GistTag)
+Liquid::Template.register_tag('gistnocache', Jekyll::GistTagNoCache)
diff --git a/plugins/haml.rb b/plugins/haml.rb
new file mode 100644
index 00000000..7e548dec
--- /dev/null
+++ b/plugins/haml.rb
@@ -0,0 +1,24 @@
+module Jekyll
+ require 'haml'
+ class HamlConverter < Converter
+ safe true
+ priority :low
+
+ def matches(ext)
+ ext =~ /haml/i
+ end
+
+ def output_ext(ext)
+ ".html"
+ end
+
+ def convert(content)
+ begin
+ engine = Haml::Engine.new(content)
+ engine.render
+ rescue StandardError => e
+ puts "!!! HAML Error: " + e.message
+ end
+ end
+ end
+end
diff --git a/plugins/include_code.rb b/plugins/include_code.rb
new file mode 100644
index 00000000..b063f14f
--- /dev/null
+++ b/plugins/include_code.rb
@@ -0,0 +1,55 @@
+# Title: Include Code Tag for Jekyll
+# Author: Brandon Mathis http://brandonmathis.com
+# Description: Import files on your filesystem into any blog post as embedded code snippets with syntax highlighting and a download link.
+# Configuration: You can set default import path in _config.yml (defaults to code_dir: downloads/code)
+#
+# Syntax {% include_code path/to/file %}
+#
+# Example:
+# {% include_code javascripts/test.js %}
+#
+# This will import test.js from source/downloads/code/javascripts/test.js
+# and output the contents in a syntax highlighted code block inside a figure,
+# with a figcaption listing the file name and download link
+#
+
+require 'pathname'
+
+module Jekyll
+
+ class IncludeCodeTag < Liquid::Tag
+ def initialize(tag_name, file, tokens)
+ super
+ @file = file.strip
+ end
+
+ def render(context)
+ code_dir = (context.registers[:site].config['code_dir'] || 'downloads/code')
+ code_path = (Pathname.new(context.registers[:site].source) + code_dir).expand_path
+ file = code_path + @file
+
+ if File.symlink?(code_path)
+ return "Code directory '#{code_path}' cannot be a symlink"
+ end
+
+ unless file.file?
+ return "File #{file} could not be found"
+ end
+
+ Dir.chdir(code_path) do
+ code = file.read
+ file_type = file.extname
+ url = "#{context.registers[:site].config['url']}/#{code_dir}/#{@file}"
+ source = "<figure role=code><figcaption><span>#{file.basename}</span> <a href='#{url}'>download</a></figcaption>\n"
+ source += "{% highlight #{file_type} %}\n" + code + "\n{% endhighlight %}</figure>"
+ partial = Liquid::Template.parse(source)
+ context.stack do
+ partial.render(context)
+ end
+ end
+ end
+ end
+
+end
+
+Liquid::Template.register_tag('include_code', Jekyll::IncludeCodeTag)
diff --git a/plugins/pullquote.rb b/plugins/pullquote.rb
new file mode 100644
index 00000000..ff576fa0
--- /dev/null
+++ b/plugins/pullquote.rb
@@ -0,0 +1,40 @@
+#
+# Author: Brandon Mathis
+# Based on the sematic pullquote technique by Maykel Loomans at http://miekd.com/articles/pull-quotes-with-html5-and-css/
+#
+# Outputs a span with a data-pullquote attribute set from the marked pullquote. Example:
+#
+# {% pullquote %}
+# When writing longform posts, I find it helpful to include pullquotes, which help those scanning a post discern whether or not a post is helpful.
+# It is important to note, {" pullquotes are merely visual in presentation and should not appear twice in the text. "} That is why it is prefered
+# to use a CSS only technique for styling pullquotes.
+# {% endpullquote %}
+# ...will output...
+# <p>
+# <span data-pullquote="pullquotes are merely visual in presentation and should not appear twice in the text.">
+# When writing longform posts, I find it helpful to include pullquotes, which help those scanning a post discern whether or not a post is helpful.
+# It is important to note, pullquotes are merely visual in presentation and should not appear twice in the text. This is why a CSS only approach # for styling pullquotes is prefered.
+# </span>
+# </p>
+#
+
+module Jekyll
+
+ class PullquoteTag < Liquid::Block
+ def initialize(tag_name, markup, tokens)
+ super
+ end
+
+ def render(context)
+ output = super
+ if output.join =~ /\{"\s*(.+)\s*"\}/
+ @quote = $1
+ "<span class='has-pullquote' data-pullquote='#{@quote}'>#{output.join.gsub(/\{"\s*|\s*"\}/, '')}</span>"
+ else
+ return "Surround your pullquote like this {! text to be quoted !}"
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('pullquote', Jekyll::PullquoteTag)
diff --git a/plugins/pygments_cache_patch.rb b/plugins/pygments_cache_patch.rb
new file mode 100644
index 00000000..09c09840
--- /dev/null
+++ b/plugins/pygments_cache_patch.rb
@@ -0,0 +1,30 @@
+#
+# Author: Raimonds Simanovskis, http://blog.rayapps.com/
+# Source URL: https://github.com/rsim/blog.rayapps.com/blob/master/_plugins/pygments_cache_patch.rb
+#
+
+require 'fileutils'
+require 'digest/md5'
+
+PYGMENTS_CACHE_DIR = File.expand_path('../../_code_cache', __FILE__)
+FileUtils.mkdir_p(PYGMENTS_CACHE_DIR)
+
+Jekyll::HighlightBlock.class_eval do
+ def render_pygments(context, code)
+ if defined?(PYGMENTS_CACHE_DIR)
+ path = File.join(PYGMENTS_CACHE_DIR, "#{@lang}-#{Digest::MD5.hexdigest(code)}.html")
+ if File.exist?(path)
+ highlighted_code = File.read(path)
+ else
+ highlighted_code = Albino.new(code, @lang).to_s(@options)
+ File.open(path, 'w') {|f| f.print(highlighted_code) }
+ end
+ else
+ highlighted_code = Albino.new(code, @lang).to_s(@options)
+ end
+ output = add_code_tags(highlighted_code, @lang)
+ output = context["pygments_prefix"] + output if context["pygments_prefix"]
+ output = output + context["pygments_suffix"] if context["pygments_suffix"]
+ output
+ end
+end
diff --git a/plugins/render_partial.rb b/plugins/render_partial.rb
new file mode 100644
index 00000000..96de97ea
--- /dev/null
+++ b/plugins/render_partial.rb
@@ -0,0 +1,52 @@
+# Title: Render Partial Tag for Jekyll
+# Author: Brandon Mathis http://brandonmathis.com
+# Description: Import files on your filesystem into any blog post and render them inline.
+# Note: Paths are relative to the source directory
+#
+# Syntax {% render_partial path/to/file %}
+#
+# Example 1:
+# {% render_partial about/_bio.markdown %}
+#
+# This will import source/about/_bio.markdown and render it inline.
+# In this example I used an underscore at the beginning of the filename to prevent Jekyll
+# from generating an about/bio.html (Jekyll doesn't convert files beginning with underscores)
+#
+# Example 2:
+# {% render_partial ../README.markdown %}
+#
+# You can use relative pathnames, to include files outside of the source directory.
+# This might be useful if you want to have a page for a project's README without having
+# to duplicated the contents
+#
+
+require 'pathname'
+
+module Jekyll
+
+ class RenderPartialTag < Liquid::Tag
+ def initialize(tag_name, file, tokens)
+ super
+ @file = file.strip
+ end
+
+ def render(context)
+ file_dir = (context.registers[:site].source || 'source')
+ file_path = Pathname.new(file_dir).expand_path
+ file = file_path + @file
+
+ unless file.file?
+ return "File #{file} could not be found"
+ end
+
+ Dir.chdir(file_path) do
+ partial = Liquid::Template.parse(file.read)
+ context.stack do
+ partial.render(context)
+ end
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('render_partial', Jekyll::RenderPartialTag)
diff --git a/plugins/sitemap_generator.rb b/plugins/sitemap_generator.rb
new file mode 100644
index 00000000..8b6cf78c
--- /dev/null
+++ b/plugins/sitemap_generator.rb
@@ -0,0 +1,308 @@
+# Sitemap.xml Generator is a Jekyll plugin that generates a sitemap.xml file by
+# traversing all of the available posts and pages.
+#
+# How To Use:
+# 1) Copy source file into your _plugins folder within your Jekyll project.
+# 2) Change modify the url variable in _config.yml to reflect your domain name.
+# 3) Run Jekyll: jekyll --server to re-generate your site.
+#
+# Variables:
+# * Change SITEMAP_FILE_NAME if you want your sitemap to be called something
+# other than sitemap.xml.
+# * Change the PAGES_INCLUDE_POSTS list to include any pages that are looping
+# through your posts (e.g. "index.html", "archive.html", etc.). This will
+# ensure that right after you make a new post, the last modified date will
+# be updated to reflect the new post.
+# * A sitemap.xml should be included in your _site folder.
+# * If there are any files you don't want included in the sitemap, add them
+# to the EXCLUDED_FILES list. The name should match the name of the source
+# file.
+# * If you want to include the optional changefreq and priority attributes,
+# simply include custom variables in the YAML Front Matter of that file.
+# The names of these custom variables are defined below in the
+# CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME and PRIORITY_CUSTOM_VARIABLE_NAME
+# constants.
+#
+# Notes:
+# * The last modified date is determined by the latest from the following:
+# system modified date of the page or post, system modified date of
+# included layout, system modified date of included layout within that
+# layout, ...
+#
+# Author: Michael Levin
+# Site: http://www.kinnetica.com
+# Distributed Under A Creative Commons License
+# - http://creativecommons.org/licenses/by/3.0/
+#
+# Modified for Octopress by John W. Long
+#
+require 'rexml/document'
+
+module Jekyll
+
+ # Change SITEMAP_FILE_NAME if you would like your sitemap file
+ # to be called something else
+ SITEMAP_FILE_NAME = "sitemap.xml"
+
+ # Any files to exclude from being included in the sitemap.xml
+ EXCLUDED_FILES = ["atom.xml"]
+
+ # Any files that include posts, so that when a new post is added, the last
+ # modified date of these pages should take that into account
+ PAGES_INCLUDE_POSTS = ["index.html"]
+
+ # Custom variable names for changefreq and priority elements
+ # These names are used within the YAML Front Matter of pages or posts
+ # for which you want to include these properties
+ CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME = "change_frequency"
+ PRIORITY_CUSTOM_VARIABLE_NAME = "priority"
+
+ class Post
+ attr_accessor :name
+
+ def full_path_to_source
+ File.join(@base, @name)
+ end
+
+ def location_on_server
+ "#{site.config['url']}#{url}"
+ end
+ end
+
+ class Page
+ attr_accessor :name
+
+ def full_path_to_source
+ File.join(@base, @dir, @name)
+ end
+
+ def location_on_server
+ location = "#{site.config['url']}#{@dir}#{url}"
+ location.gsub(/index.html$/, "")
+ end
+ end
+
+ class Layout
+ def full_path_to_source
+ File.join(@base, @name)
+ end
+ end
+
+ # Recover from strange exception when starting server without --auto
+ class SitemapFile < StaticFile
+ def write(dest)
+ begin
+ super(dest)
+ rescue
+ end
+
+ true
+ end
+ end
+
+ class SitemapGenerator < Generator
+
+ # Valid values allowed by sitemap.xml spec for change frequencies
+ VALID_CHANGE_FREQUENCY_VALUES = ["always", "hourly", "daily", "weekly",
+ "monthly", "yearly", "never"]
+
+ # Goes through pages and posts and generates sitemap.xml file
+ #
+ # Returns nothing
+ def generate(site)
+ sitemap = REXML::Document.new << REXML::XMLDecl.new("1.0", "UTF-8")
+
+ urlset = REXML::Element.new "urlset"
+ urlset.add_attribute("xmlns",
+ "http://www.sitemaps.org/schemas/sitemap/0.9")
+
+ @last_modified_post_date = fill_posts(site, urlset)
+ fill_pages(site, urlset)
+
+ sitemap.add_element(urlset)
+
+ # File I/O: create sitemap.xml file and write out pretty-printed XML
+ file = File.new(File.join(site.dest, SITEMAP_FILE_NAME), "w")
+ formatter = REXML::Formatters::Pretty.new(4)
+ formatter.compact = true
+ formatter.write(sitemap, file)
+ file.close
+
+ # Keep the sitemap.xml file from being cleaned by Jekyll
+ site.static_files << Jekyll::SitemapFile.new(site, site.dest, "/", SITEMAP_FILE_NAME)
+ end
+
+ # Create url elements for all the posts and find the date of the latest one
+ #
+ # Returns last_modified_date of latest post
+ def fill_posts(site, urlset)
+ last_modified_date = nil
+ site.posts.each do |post|
+ if !excluded?(post.name)
+ url = fill_url(site, post)
+ urlset.add_element(url)
+ end
+
+ path = post.full_path_to_source
+ date = File.mtime(path)
+ last_modified_date = date if last_modified_date == nil or date > last_modified_date
+ end
+
+ last_modified_date
+ end
+
+ # Create url elements for all the normal pages and find the date of the
+ # index to use with the pagination pages
+ #
+ # Returns last_modified_date of index page
+ def fill_pages(site, urlset)
+ site.pages.each do |page|
+ if !excluded?(page.name)
+ path = page.full_path_to_source
+ if File.exists?(path)
+ url = fill_url(site, page)
+ urlset.add_element(url)
+ end
+ end
+ end
+ end
+
+ # Fill data of each URL element: location, last modified,
+ # change frequency (optional), and priority.
+ #
+ # Returns url REXML::Element
+ def fill_url(site, page_or_post)
+ url = REXML::Element.new "url"
+
+ loc = fill_location(page_or_post)
+ url.add_element(loc)
+
+ lastmod = fill_last_modified(site, page_or_post)
+ url.add_element(lastmod) if lastmod
+
+ if (page_or_post.data[CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME])
+ change_frequency =
+ page_or_post.data[CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME].downcase
+
+ if (valid_change_frequency?(change_frequency))
+ changefreq = REXML::Element.new "changefreq"
+ changefreq.text = change_frequency
+ url.add_element(changefreq)
+ else
+ puts "ERROR: Invalid Change Frequency In #{page_or_post.name}"
+ end
+ end
+
+ if (page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME])
+ priority_value = page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME]
+ if valid_priority?(priority_value)
+ priority = REXML::Element.new "priority"
+ priority.text = page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME]
+ url.add_element(priority)
+ else
+ puts "ERROR: Invalid Priority In #{page_or_post.name}"
+ end
+ end
+
+ url
+ end
+
+ # Get URL location of page or post
+ #
+ # Returns the location of the page or post
+ def fill_location(page_or_post)
+ loc = REXML::Element.new "loc"
+ loc.text = page_or_post.location_on_server
+
+ loc
+ end
+
+ # Fill lastmod XML element with the last modified date for the page or post.
+ #
+ # Returns lastmod REXML::Element or nil
+ def fill_last_modified(site, page_or_post)
+ path = page_or_post.full_path_to_source
+
+ lastmod = REXML::Element.new "lastmod"
+ date = File.mtime(path)
+ latest_date = find_latest_date(date, site, page_or_post)
+
+ if @last_modified_post_date == nil
+ # This is a post
+ lastmod.text = latest_date.iso8601
+ else
+ # This is a page
+ if posts_included?(page_or_post.name)
+ # We want to take into account the last post date
+ final_date = greater_date(latest_date, @last_modified_post_date)
+ lastmod.text = final_date.iso8601
+ else
+ lastmod.text = latest_date.iso8601
+ end
+ end
+ lastmod
+ end
+
+ # Go through the page/post and any implemented layouts and get the latest
+ # modified date
+ #
+ # Returns formatted output of latest date of page/post and any used layouts
+ def find_latest_date(latest_date, site, page_or_post)
+ layouts = site.layouts
+ layout = layouts[page_or_post.data["layout"]]
+ while layout
+ path = layout.full_path_to_source
+ date = File.mtime(path)
+
+ latest_date = date if (date > latest_date)
+
+ layout = layouts[layout.data["layout"]]
+ end
+
+ latest_date
+ end
+
+ # Which of the two dates is later
+ #
+ # Returns latest of two dates
+ def greater_date(date1, date2)
+ if (date1 >= date2)
+ date1
+ else
+ date2
+ end
+ end
+
+ # Is the page or post listed as something we want to exclude?
+ #
+ # Returns boolean
+ def excluded?(name)
+ EXCLUDED_FILES.include? name
+ end
+
+ def posts_included?(name)
+ PAGES_INCLUDE_POSTS.include? name
+ end
+
+ # Is the change frequency value provided valid according to the spec
+ #
+ # Returns boolean
+ def valid_change_frequency?(change_frequency)
+ VALID_CHANGE_FREQUENCY_VALUES.include? change_frequency
+ end
+
+ # Is the priority value provided valid according to the spec
+ #
+ # Returns boolean
+ def valid_priority?(priority)
+ begin
+ priority_val = Float(priority)
+ return true if priority_val >= 0.0 and priority_val <= 1.0
+ rescue ArgumentError
+ end
+
+ false
+ end
+ end
+end
+
diff --git a/plugins/titlecase.rb b/plugins/titlecase.rb
new file mode 100644
index 00000000..103bf702
--- /dev/null
+++ b/plugins/titlecase.rb
@@ -0,0 +1,36 @@
+class String
+ def titlecase
+ small_words = %w(a an and as at but by en for if in of on or the to v v. via vs vs.)
+
+ x = split(" ").map do |word|
+ # note: word could contain non-word characters!
+ # downcase all small_words, capitalize the rest
+ small_words.include?(word.gsub(/\W/, "").downcase) ? word.downcase! : word.smart_capitalize!
+ word
+ end
+ # capitalize first and last words
+ x.first.to_s.smart_capitalize!
+ x.last.to_s.smart_capitalize!
+ # small words after colons are capitalized
+ x.join(" ").gsub(/:\s?(\W*#{small_words.join("|")}\W*)\s/) { ": #{$1.smart_capitalize} " }
+ end
+
+ def titlecase!
+ replace(titlecase)
+ end
+
+ def smart_capitalize
+ # ignore any leading crazy characters and capitalize the first real character
+ if self =~ /^['"\(\[']*([a-z])/
+ i = index($1)
+ x = self[i,self.length]
+ # word with capitals and periods mid-word are left alone
+ self[i,1] = self[i,1].upcase unless x =~ /[A-Z]/ or x =~ /\.\w+/
+ end
+ self
+ end
+
+ def smart_capitalize!
+ replace(smart_capitalize)
+ end
+end