| ... | ... | @@ -25,9 +25,13 @@ task :install, :theme do |t, args| | 
| 25 | 25 | # copy theme into working Jekyll directories | 
| 26 | 26 | theme = args.theme || 'classic' | 
| 27 | 27 | puts "## Copying "+theme+" theme to Jekyll paths" | 
| 28 | - system "cp -R themes/"+theme+"/source source" | |
| 29 | - system "cp -R themes/"+theme+"/sass sass" | |
| 30 | - # system "cp -R themes/"+theme+"/_plugins/ _plugins/" | |
| 28 | +  system "mkdir -p #{source}; cp -R themes/"+theme+"/source/ #{source}/" | |
| 29 | + system "mkdir -p sass; cp -R themes/"+theme+"/sass/ sass/" | |
| 30 | + system "mkdir -p _plugins; cp -R themes/"+theme+"/_plugins/ _plugins/" | |
| 31 | +  system "mkdir -p #{source}/_posts"; | |
| 32 | +  puts "## Layouts, images, and javascritps from the #{theme} theme have been installed into ./#{source}" | |
| 33 | +  puts "## Sass stylesheet sources from the #{theme} theme have been installed into ./sass" | |
| 34 | +  puts "## Plugins from the #{theme} theme have been installed into ./_plugins" | |
| 31 | 35 | end | 
| 32 | 36 |  | 
| 33 | 37 | ####################### | 
| 34 | 38 | deleted file mode 100644 | 
| ... | ... | @@ -1,109 +0,0 @@ | 
| 1 | -# | |
| 2 | -# Author: Josediaz Gonzalez - https://github.com/josegonzalez | |
| 3 | -# Source URL: https://github.com/josegonzalez/josediazgonzalez.com/blob/master/_plugins/blockquote.rb | |
| 4 | -# Modified by Brandon Mathis | |
| 5 | -# | |
| 6 | -require './_plugins/titlecase.rb' | |
| 7 | -module Jekyll | |
| 8 | - | |
| 9 | - # Outputs a string with a given attribution as a quote | |
| 10 | - # | |
| 11 | -  #   {% blockquote John Paul Jones %} | |
| 12 | - # Monkeys! | |
| 13 | -  #   {% endblockquote %} | |
| 14 | - # ... | |
| 15 | - # <blockquote> | |
| 16 | - # Monkeys! | |
| 17 | - # <br /> | |
| 18 | - # John Paul Jones | |
| 19 | - # </blockquote> | |
| 20 | - # | |
| 21 | - class Blockquote < Liquid::Block | |
| 22 | - FullCiteWithTitle = /([\w\s]+)(https?:\/\/)(\S+\s)([\w\s]+)/i | |
| 23 | - FullCite = /([\w\s]+)(https?:\/\/)(\S+)/i | |
| 24 | - Author = /([\w\s]+)/ | |
| 25 | - | |
| 26 | - def initialize(tag_name, markup, tokens) | |
| 27 | - @by = nil | |
| 28 | - @source = nil | |
| 29 | - @title = nil | |
| 30 | - if markup =~ FullCiteWithTitle | |
| 31 | - @by = $1 | |
| 32 | - @source = $2 + $3 | |
| 33 | - @title = $4.titlecase | |
| 34 | - elsif markup =~ FullCite | |
| 35 | - @by = $1 | |
| 36 | - @source = $2 + $3 | |
| 37 | - elsif markup =~ Author | |
| 38 | - @by = $1 | |
| 39 | - end | |
| 40 | - super | |
| 41 | - end | |
| 42 | - | |
| 43 | - def render(context) | |
| 44 | - output = super | |
| 45 | - if @by.nil? | |
| 46 | - '<blockquote><p>' + output.join + '</p></blockquote>' | |
| 47 | - elsif !@title.nil? | |
| 48 | - '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + '<a class="source" href="' + @source + '">' + @title + '</a></cite></p>' | |
| 49 | - elsif !@source.nil? | |
| 50 | - '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + '<a class="source" href="' + @source + '">source</a></cite></p>' | |
| 51 | - else | |
| 52 | - '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong></cite></p>' | |
| 53 | - end | |
| 54 | - end | |
| 55 | - end | |
| 56 | - | |
| 57 | - # Outputs a string with a given attribution as a pullquote | |
| 58 | - # | |
| 59 | -  #   {% blockquote John Paul Jones %} | |
| 60 | - # Monkeys! | |
| 61 | -  #   {% endblockquote %} | |
| 62 | - # ... | |
| 63 | - # <blockquote class="pullquote"> | |
| 64 | - # Monkeys! | |
| 65 | - # <br /> | |
| 66 | - # John Paul Jones | |
| 67 | - # </blockquote> | |
| 68 | - # | |
| 69 | - class Pullquote < Liquid::Block | |
| 70 | - FullCiteWithTitle = /([\w\s]+)(http:\/\/|https:\/\/)(\S+)([\w\s]+)/i | |
| 71 | - FullCite = /([\w\s]+)(http:\/\/|https:\/\/)(\S+)/i | |
| 72 | - Author = /([\w\s]+)/ | |
| 73 | - | |
| 74 | - def initialize(tag_name, markup, tokens) | |
| 75 | - @by = nil | |
| 76 | - @source = nil | |
| 77 | - @title = nil | |
| 78 | - if markup =~ FullCiteWithTitle | |
| 79 | - @by = $1 | |
| 80 | - @source = $2 + $3 | |
| 81 | - @title = $4 | |
| 82 | - elsif markup =~ FullCite | |
| 83 | - @by = $1 | |
| 84 | - @source = $2 + $3 | |
| 85 | - elsif markup =~ Author | |
| 86 | - @by = $1 | |
| 87 | - end | |
| 88 | - super | |
| 89 | - end | |
| 90 | - | |
| 91 | - def render(context) | |
| 92 | - output = super | |
| 93 | - if @by.nil? | |
| 94 | - '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' | |
| 95 | - elsif @title | |
| 96 | - '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + ' <a class="source" href="' + @source + '">' + @title + '</a></cite></p>' | |
| 97 | - elsif @source | |
| 98 | - '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + ' <a class="source" href="' + @source + '">source</a></cite></p>' | |
| 99 | - elsif @by | |
| 100 | - '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong></cite></p>' | |
| 101 | - end | |
| 102 | - end | |
| 103 | - end | |
| 104 | -end | |
| 105 | - | |
| 106 | -Liquid::Template.register_tag('blockquote', Jekyll::Blockquote) | |
| 107 | -Liquid::Template.register_tag('pullquote', Jekyll::Pullquote) | |
| 108 | - | |
| 109 | - | 
| 110 | 1 | deleted file mode 100644 | 
| ... | ... | @@ -1,65 +0,0 @@ | 
| 1 | -module Jekyll | |
| 2 | - | |
| 3 | - class CategoryIndex < Page | |
| 4 | - def initialize(site, base, dir, category) | |
| 5 | - @site = site | |
| 6 | - @base = base | |
| 7 | - @dir = dir | |
| 8 | - @name = 'index.html' | |
| 9 | - | |
| 10 | - self.process(@name) | |
| 11 | - self.read_yaml(File.join(base, '_layouts'), 'category_index.html') | |
| 12 | - self.data['category'] = category | |
| 13 | - | |
| 14 | - category_title_prefix = site.config['category_title_prefix'] || 'Category: ' | |
| 15 | -      self.data['title'] = "#{category_title_prefix}#{category}" | |
| 16 | - end | |
| 17 | - end | |
| 18 | - | |
| 19 | - class CategoryList < Page | |
| 20 | - def initialize(site, base, dir, categories) | |
| 21 | - @site = site | |
| 22 | - @base = base | |
| 23 | - @dir = dir | |
| 24 | - @name = 'index.html' | |
| 25 | - | |
| 26 | - self.process(@name) | |
| 27 | - self.read_yaml(File.join(base, '_layouts'), 'category_list.html') | |
| 28 | - self.data['categories'] = categories | |
| 29 | - end | |
| 30 | - end | |
| 31 | - | |
| 32 | - class CategoryGenerator < Generator | |
| 33 | - safe true | |
| 34 | - | |
| 35 | - def generate(site) | |
| 36 | - if site.layouts.key? 'category_index' | |
| 37 | - dir = site.config['category_dir'] || 'categories' | |
| 38 | - site.categories.keys.each do |category| | |
| 39 | - write_category_index(site, File.join(dir, category.gsub(/\s/, "-").gsub(/[^\w-]/, '').downcase), category) | |
| 40 | - end | |
| 41 | - end | |
| 42 | - | |
| 43 | - if site.layouts.key? 'category_list' | |
| 44 | - dir = site.config['category_dir'] || 'categories' | |
| 45 | - write_category_list(site, dir, site.categories.keys.sort) | |
| 46 | - end | |
| 47 | - end | |
| 48 | - | |
| 49 | - def write_category_index(site, dir, category) | |
| 50 | - index = CategoryIndex.new(site, site.source, dir, category) | |
| 51 | - index.render(site.layouts, site.site_payload) | |
| 52 | - index.write(site.dest) | |
| 53 | - site.static_files << index | |
| 54 | - end | |
| 55 | - | |
| 56 | - def write_category_list(site, dir, categories) | |
| 57 | - index = CategoryList.new(site, site.source, dir, categories) | |
| 58 | - index.render(site.layouts, site.site_payload) | |
| 59 | - index.write(site.dest) | |
| 60 | - site.static_files << index | |
| 61 | - end | |
| 62 | - end | |
| 63 | - | |
| 64 | -end | |
| 65 | - | 
| 2 | 1 | deleted file mode 100644 | 
| ... | ... | @@ -1,59 +0,0 @@ | 
| 1 | -#custom filters for Octopress | |
| 2 | - | |
| 3 | -module OctopressFilters | |
| 4 | - def exerpt(input, url, url_text="Reade more…", permalink_text=false) | |
| 5 | - if input.index(/<!--\s?more\s?-->/i) | |
| 6 | -      input.split(/<!--\s?more\s?-->/i)[0] + "<p><a href='#{url}'>#{url_text}</a></p>" | |
| 7 | - elsif permalink_text | |
| 8 | -      input + "<p><a href='#{url}'>#{permalink_text}</a></p>" | |
| 9 | - else | |
| 10 | - input | |
| 11 | - end | |
| 12 | - end | |
| 13 | - def full_urls(input, url='') | |
| 14 | -    input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]+)/ do | |
| 15 | - $1+url+$3 | |
| 16 | - end | |
| 17 | - end | |
| 18 | - def search_url(input) | |
| 19 | - input.gsub /(http:\/\/)(\S+)/ do | |
| 20 | - $2 | |
| 21 | - end | |
| 22 | - end | |
| 23 | - def smart_quotes(input) | |
| 24 | - require 'rubypants' | |
| 25 | - RubyPants.new(input).to_html | |
| 26 | - end | |
| 27 | - def titlecase(input) | |
| 28 | - input.titlecase | |
| 29 | - end | |
| 30 | - def datetime(date) | |
| 31 | - if date.class == String | |
| 32 | - date = Time.parse(date) | |
| 33 | - end | |
| 34 | - date | |
| 35 | - end | |
| 36 | - def ordinalize(date) | |
| 37 | - date = datetime(date) | |
| 38 | -    "#{date.strftime('%B')} #{ordinal(date.strftime('%e').to_i)}, #{date.strftime('%Y')}" | |
| 39 | - end | |
| 40 | - def ordinal(number) | |
| 41 | - if (11..13).include?(number.to_i % 100) | |
| 42 | -      "#{number}<span>th</span>" | |
| 43 | - else | |
| 44 | - case number.to_i % 10 | |
| 45 | -      when 1; "#{number}<span>st</span>" | |
| 46 | -      when 2; "#{number}<span>nd<span>" | |
| 47 | -      when 3; "#{number}<span>rd</span>" | |
| 48 | -      else    "#{number}<span>th</span>" | |
| 49 | - end | |
| 50 | - end | |
| 51 | - end | |
| 52 | -  #YearlyPost = Struct.new('YearlyPost', :year, :posts) | |
| 53 | - def yearly_posts(site) | |
| 54 | -    #site.posts.reverse.group_by { |p| p.date.strftime("%Y") }.map { |k,v| YearlyPost.new(k,v) } | |
| 55 | - site | |
| 56 | - end | |
| 57 | -end | |
| 58 | -Liquid::Template.register_filter OctopressFilters | |
| 59 | - | 
| 60 | 1 | deleted file mode 100644 | 
| ... | ... | @@ -1,133 +0,0 @@ | 
| 1 | -# Jekyll sitemap page generator. | |
| 2 | -# http://recursive-design.com/projects/jekyll-plugins/ | |
| 3 | -# | |
| 4 | -# Version: 0.1.3 (201101061053) | |
| 5 | -# | |
| 6 | -# Copyright (c) 2010 Dave Perrett, http://recursive-design.com/ | |
| 7 | -# Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) | |
| 8 | -# | |
| 9 | -# A generator that creates a sitemap.xml page for jekyll sites, suitable for submission to | |
| 10 | -# google etc. | |
| 11 | -# | |
| 12 | -# To use it, simply drop this script into the _plugins directory of your Jekyll site. | |
| 13 | -# | |
| 14 | -# When you compile your jekyll site, this plugin will loop through the list of pages in your | |
| 15 | -# site, and generate an entry in sitemap.xml for each one. | |
| 16 | - | |
| 17 | -require 'pathname' | |
| 18 | - | |
| 19 | -module Jekyll | |
| 20 | - | |
| 21 | - | |
| 22 | - # Monkey-patch an accessor for a page's containing folder, since | |
| 23 | - # we need it to generate the sitemap. | |
| 24 | - class Page | |
| 25 | - def subfolder | |
| 26 | - @dir | |
| 27 | - end | |
| 28 | - end | |
| 29 | - | |
| 30 | - | |
| 31 | - # Sub-class Jekyll::StaticFile to allow recovery from unimportant exception | |
| 32 | - # when writing the sitemap file. | |
| 33 | - class StaticSitemapFile < StaticFile | |
| 34 | - def write(dest) | |
| 35 | - super(dest) rescue ArgumentError | |
| 36 | - true | |
| 37 | - end | |
| 38 | - end | |
| 39 | - | |
| 40 | - | |
| 41 | - # Generates a sitemap.xml file containing URLs of all pages and posts. | |
| 42 | - class SitemapGenerator < Generator | |
| 43 | - safe true | |
| 44 | - priority :low | |
| 45 | - | |
| 46 | - # Domain that you are generating the sitemap for - update this to match your site. | |
| 47 | - | |
| 48 | - # Generates the sitemap.xml file. | |
| 49 | - # | |
| 50 | - # +site+ is the global Site object. | |
| 51 | - def generate(site) | |
| 52 | - # Create the destination folder if necessary. | |
| 53 | - site_folder = site.config['destination'] | |
| 54 | - unless File.directory?(site_folder) | |
| 55 | - p = Pathname.new(site_folder) | |
| 56 | - p.mkdir | |
| 57 | - end | |
| 58 | - | |
| 59 | - # Write the contents of sitemap.xml. | |
| 60 | - File.open(File.join(site_folder, 'sitemap.xml'), 'w') do |f| | |
| 61 | - f.write(generate_header()) | |
| 62 | - f.write(generate_content(site)) | |
| 63 | - f.write(generate_footer()) | |
| 64 | - f.close | |
| 65 | - end | |
| 66 | - | |
| 67 | - # Add a static file entry for the zip file, otherwise Site::cleanup will remove it. | |
| 68 | - site.static_files << Jekyll::StaticSitemapFile.new(site, site.dest, '/', 'sitemap.xml') | |
| 69 | - end | |
| 70 | - | |
| 71 | - private | |
| 72 | - | |
| 73 | - # Returns the XML header. | |
| 74 | - def generate_header | |
| 75 | - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">" | |
| 76 | - end | |
| 77 | - | |
| 78 | - # Returns a string containing the the XML entries. | |
| 79 | - # | |
| 80 | - # +site+ is the global Site object. | |
| 81 | - def generate_content(site) | |
| 82 | - result = '' | |
| 83 | - | |
| 84 | - base_url = site.config['url'] | |
| 85 | - | |
| 86 | - # First, try to find any stand-alone pages. | |
| 87 | -      site.pages.each{ |page| | |
| 88 | - path = page.subfolder + '/' + page.name | |
| 89 | - mod_date = File.mtime(site.source + path) | |
| 90 | - | |
| 91 | - # Remove the trailing 'index.html' if there is one, and just output the folder name. | |
| 92 | - if path=~/index.html$/ | |
| 93 | - path = path[0..-11] | |
| 94 | - end | |
| 95 | - | |
| 96 | - unless path =~/error/ | |
| 97 | - result += entry(base_url, path, mod_date) | |
| 98 | - end | |
| 99 | - } | |
| 100 | - | |
| 101 | - # Next, find all the posts. | |
| 102 | - posts = site.site_payload['site']['posts'] | |
| 103 | - for post in posts do | |
| 104 | - result += entry(base_url, post.id, post.date) | |
| 105 | - end | |
| 106 | - | |
| 107 | - result | |
| 108 | - end | |
| 109 | - | |
| 110 | - # Returns the XML footer. | |
| 111 | - def generate_footer | |
| 112 | - "\n</urlset>" | |
| 113 | - end | |
| 114 | - | |
| 115 | - # Creates an XML entry from the given path and date. | |
| 116 | - # | |
| 117 | - # +path+ is the URL path to the page. | |
| 118 | - # +date+ is the date the file was modified (in the case of regular pages), or published (for blog posts). | |
| 119 | - def entry(base_url, path, date) | |
| 120 | - # Force extensions to .html from markdown, textile. | |
| 121 | - path = path.gsub(/\.(markdown|textile)$/i, '.html') | |
| 122 | - " | |
| 123 | - <url> | |
| 124 | -      <loc>#{base_url}#{path}</loc> | |
| 125 | -      <lastmod>#{date.strftime("%Y-%m-%d")}</lastmod> | |
| 126 | - </url>" | |
| 127 | - end | |
| 128 | - | |
| 129 | - end | |
| 130 | - | |
| 131 | -end | |
| 132 | - | |
| 133 | - | 
| 134 | 1 | deleted file mode 100644 | 
| ... | ... | @@ -1,83 +0,0 @@ | 
| 1 | -# Nicked from Brandon Tilly | |
| 2 | -# Gist https://gist.github.com/803483 | |
| 3 | -# Post http://brandontilley.com/2011/01/31/gist-tag-for-jekyll.html | |
| 4 | -# | |
| 5 | -# Example usage: {% gist 803483 gist_tag.rb %} //embeds a gist for this plugin | |
| 6 | - | |
| 7 | -require 'digest/md5' | |
| 8 | -require 'net/https' | |
| 9 | -require 'uri' | |
| 10 | - | |
| 11 | -module Jekyll | |
| 12 | - class GistTag < Liquid::Tag | |
| 13 | - def initialize(tag_name, text, token) | |
| 14 | - super | |
| 15 | -      system('mkdir -p .gist_cache') | |
| 16 | - @text = text | |
| 17 | - @cache = true | |
| 18 | - @cache_folder = File.expand_path "../.gist_cache", File.dirname(__FILE__) | |
| 19 | - end | |
| 20 | - | |
| 21 | - def render(context) | |
| 22 | - return "" unless @text =~ /([\d]*) (.*)/ | |
| 23 | - | |
| 24 | - gist, file = $1.strip, $2.strip | |
| 25 | -      script_url = "https://gist.github.com/#{gist}.js?file=#{file}" | |
| 26 | - | |
| 27 | - code = get_cached_gist(gist, file) || get_gist_from_web(gist, file) | |
| 28 | - code = code.gsub "<", "<" | |
| 29 | -      string     = "<script src='#{script_url}'></script>" | |
| 30 | -      string    += "<noscript><pre><code>#{code}</code></pre></noscript>" | |
| 31 | - return string | |
| 32 | - end | |
| 33 | - | |
| 34 | - def get_gist_url_for(gist, file) | |
| 35 | -      "https://gist.github.com/raw/#{gist}/#{file}" | |
| 36 | - end | |
| 37 | - | |
| 38 | - def cache_gist(gist, file, data) | |
| 39 | - file = get_cache_file_for gist, file | |
| 40 | - File.open(file, "w+") do |f| | |
| 41 | - f.write(data) | |
| 42 | - end | |
| 43 | - end | |
| 44 | - | |
| 45 | - def get_cached_gist(gist, file) | |
| 46 | - return nil if @cache == false | |
| 47 | - file = get_cache_file_for gist, file | |
| 48 | - return nil unless File.exist?(file) | |
| 49 | - return File.new(file).readlines.join | |
| 50 | - end | |
| 51 | - | |
| 52 | - def get_cache_file_for(gist, file) | |
| 53 | - gist.gsub! /[^a-zA-Z0-9\-_\.]/, '' | |
| 54 | - file.gsub! /[^a-zA-Z0-9\-_\.]/, '' | |
| 55 | -      md5 = Digest::MD5.hexdigest "#{gist}-#{file}" | |
| 56 | -      File.join @cache_folder, "#{gist}-#{file}-#{md5}.cache" | |
| 57 | - end | |
| 58 | - | |
| 59 | - def get_gist_from_web(gist, file) | |
| 60 | - gist_url = get_gist_url_for(gist, file) | |
| 61 | - raw_uri = URI.parse(gist_url) | |
| 62 | - https = Net::HTTP.new(raw_uri.host, raw_uri.port) | |
| 63 | - https.use_ssl = true | |
| 64 | - https.verify_mode = OpenSSL::SSL::VERIFY_NONE | |
| 65 | - request = Net::HTTP::Get.new(raw_uri.request_uri) | |
| 66 | - data = https.request(request) | |
| 67 | - data = data.body | |
| 68 | - cache_gist(gist, file, data) unless @cache == false | |
| 69 | - data | |
| 70 | - end | |
| 71 | - end | |
| 72 | - | |
| 73 | - class GistTagNoCache < GistTag | |
| 74 | - def initialize(tag_name, text, token) | |
| 75 | - super | |
| 76 | - @cache = false | |
| 77 | - end | |
| 78 | - end | |
| 79 | -end | |
| 80 | - | |
| 81 | -Liquid::Template.register_tag('gist', Jekyll::GistTag) | |
| 82 | -Liquid::Template.register_tag('gistnocache', Jekyll::GistTagNoCache) | |
| 83 | - | 
| 84 | 1 | deleted file mode 100644 | 
| ... | ... | @@ -1,24 +0,0 @@ | 
| 1 | -module Jekyll | |
| 2 | - require 'haml' | |
| 3 | - class HamlConverter < Converter | |
| 4 | - safe true | |
| 5 | - priority :low | |
| 6 | - | |
| 7 | - def matches(ext) | |
| 8 | - ext =~ /haml/i | |
| 9 | - end | |
| 10 | - | |
| 11 | - def output_ext(ext) | |
| 12 | - ".html" | |
| 13 | - end | |
| 14 | - | |
| 15 | - def convert(content) | |
| 16 | - begin | |
| 17 | - engine = Haml::Engine.new(content) | |
| 18 | - engine.render | |
| 19 | - rescue StandardError => e | |
| 20 | - puts "!!! HAML Error: " + e.message | |
| 21 | - end | |
| 22 | - end | |
| 23 | - end | |
| 24 | -end | 
| 25 | 1 | deleted file mode 100644 | 
| ... | ... | @@ -1,49 +0,0 @@ | 
| 1 | -## | |
| 2 | -## Author: Jose Gonzalez - https://github.com/josegonzalez | |
| 3 | -## Source URL: https://github.com/josegonzalez/josediazgonzalez.com/blob/master/_plugins/iterator.rb | |
| 4 | -## | |
| 5 | - | |
| 6 | -#module Jekyll | |
| 7 | - #class Site | |
| 8 | - #alias_method :orig_site_payload, :site_payload | |
| 9 | - | |
| 10 | - ## Constuct an array of hashes that will allow the user, using Liquid, to | |
| 11 | - ## iterate through the keys of _kv_hash_ and be able to iterate through the | |
| 12 | - ## elements under each key. | |
| 13 | - ## | |
| 14 | - ## Example: | |
| 15 | -    ##   categories = { 'Ruby' => [<Post>, <Post>] } | |
| 16 | - ## make_iterable(categories, :index => 'name', :items => 'posts') | |
| 17 | - ## Will allow the user to iterate through all categories and then iterate | |
| 18 | - ## though each post in the current category like so: | |
| 19 | -    ##   {% for category in site.categories %} | |
| 20 | -    ##     h1. {{ category.name }} | |
| 21 | - ## <ul> | |
| 22 | -    ##       {% for post in category.posts %} | |
| 23 | -    ##         <li>{{ post.title }}</li> | |
| 24 | -    ##       {% endfor %} | |
| 25 | - ## </ul> | |
| 26 | -    ##   {% endfor %} | |
| 27 | - ## | |
| 28 | -    ## Returns [ {<index> => <kv_hash_key>, <items> => kv_hash[<kv_hash_key>]}, ... ] | |
| 29 | - | |
| 30 | - #def make_iterable(kv_hash, options) | |
| 31 | -      #options = {:index => 'name', :items => 'items'}.merge(options) | |
| 32 | - #result = [] | |
| 33 | - #kv_hash.sort.each do |key, value| | |
| 34 | -        #result << { options[:index] => key, options[:items] => value } | |
| 35 | - #end | |
| 36 | - #result | |
| 37 | - #end | |
| 38 | - | |
| 39 | - #def site_payload | |
| 40 | - #payload = orig_site_payload | |
| 41 | -      #payload['site']['iterable'].merge!({ | |
| 42 | - #'categories' => make_iterable(self.categories, :index => 'name', :items => 'posts'), | |
| 43 | - #'tags' => make_iterable(self.tags, :index => 'name', :items => 'posts') | |
| 44 | - #}) | |
| 45 | - #payload | |
| 46 | - #end | |
| 47 | - | |
| 48 | - #end | |
| 49 | -#end | 
| 50 | 1 | deleted file mode 100644 | 
| ... | ... | @@ -1,30 +0,0 @@ | 
| 1 | -# | |
| 2 | -# Author: Raimonds Simanovskis, http://blog.rayapps.com/ | |
| 3 | -# Source URL: https://github.com/rsim/blog.rayapps.com/blob/master/_plugins/pygments_cache_patch.rb | |
| 4 | -# | |
| 5 | - | |
| 6 | -require 'fileutils' | |
| 7 | -require 'digest/md5' | |
| 8 | - | |
| 9 | -PYGMENTS_CACHE_DIR = File.expand_path('../../_cache', __FILE__) | |
| 10 | -FileUtils.mkdir_p(PYGMENTS_CACHE_DIR) | |
| 11 | - | |
| 12 | -Jekyll::HighlightBlock.class_eval do | |
| 13 | - def render_pygments(context, code) | |
| 14 | - if defined?(PYGMENTS_CACHE_DIR) | |
| 15 | -      path = File.join(PYGMENTS_CACHE_DIR, "#{@lang}-#{Digest::MD5.hexdigest(code)}.html") | |
| 16 | - if File.exist?(path) | |
| 17 | - highlighted_code = File.read(path) | |
| 18 | - else | |
| 19 | - highlighted_code = Albino.new(code, @lang).to_s(@options) | |
| 20 | -        File.open(path, 'w') {|f| f.print(highlighted_code) } | |
| 21 | - end | |
| 22 | - else | |
| 23 | - highlighted_code = Albino.new(code, @lang).to_s(@options) | |
| 24 | - end | |
| 25 | - output = add_code_tags(highlighted_code, @lang) | |
| 26 | - output = context["pygments_prefix"] + output if context["pygments_prefix"] | |
| 27 | - output = output + context["pygments_suffix"] if context["pygments_suffix"] | |
| 28 | - output | |
| 29 | - end | |
| 30 | -end | 
| 31 | 1 | deleted file mode 100644 | 
| ... | ... | @@ -1,36 +0,0 @@ | 
| 1 | -class String | |
| 2 | - def titlecase | |
| 3 | - small_words = %w(a an and as at but by en for if in of on or the to v v. via vs vs.) | |
| 4 | - | |
| 5 | -    x = split(" ").map do |word| | |
| 6 | - # note: word could contain non-word characters! | |
| 7 | - # downcase all small_words, capitalize the rest | |
| 8 | - small_words.include?(word.gsub(/\W/, "").downcase) ? word.downcase! : word.smart_capitalize! | |
| 9 | - word | |
| 10 | - end | |
| 11 | - # capitalize first and last words | |
| 12 | - x.first.to_s.smart_capitalize! | |
| 13 | - x.last.to_s.smart_capitalize! | |
| 14 | - # small words after colons are capitalized | |
| 15 | -    x.join(" ").gsub(/:\s?(\W*#{small_words.join("|")}\W*)\s/) { ": #{$1.smart_capitalize} " } | |
| 16 | - end | |
| 17 | - | |
| 18 | - def titlecase! | |
| 19 | - replace(titlecase) | |
| 20 | - end | |
| 21 | - | |
| 22 | - def smart_capitalize | |
| 23 | - # ignore any leading crazy characters and capitalize the first real character | |
| 24 | - if self =~ /^['"\(\[']*([a-z])/ | |
| 25 | - i = index($1) | |
| 26 | - x = self[i,self.length] | |
| 27 | - # word with capitals and periods mid-word are left alone | |
| 28 | - self[i,1] = self[i,1].upcase unless x =~ /[A-Z]/ or x =~ /\.\w+/ | |
| 29 | - end | |
| 30 | - self | |
| 31 | - end | |
| 32 | - | |
| 33 | - def smart_capitalize! | |
| 34 | - replace(smart_capitalize) | |
| 35 | - end | |
| 36 | -end | 
| 37 | 1 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,109 @@ | 
| 0 | +# | |
| 1 | +# Author: Josediaz Gonzalez - https://github.com/josegonzalez | |
| 2 | +# Source URL: https://github.com/josegonzalez/josediazgonzalez.com/blob/master/_plugins/blockquote.rb | |
| 3 | +# Modified by Brandon Mathis | |
| 4 | +# | |
| 5 | +require './_plugins/titlecase.rb' | |
| 6 | +module Jekyll | |
| 7 | + | |
| 8 | + # Outputs a string with a given attribution as a quote | |
| 9 | + # | |
| 10 | +  #   {% blockquote John Paul Jones %} | |
| 11 | + # Monkeys! | |
| 12 | +  #   {% endblockquote %} | |
| 13 | + # ... | |
| 14 | + # <blockquote> | |
| 15 | + # Monkeys! | |
| 16 | + # <br /> | |
| 17 | + # John Paul Jones | |
| 18 | + # </blockquote> | |
| 19 | + # | |
| 20 | + class Blockquote < Liquid::Block | |
| 21 | + FullCiteWithTitle = /([\w\s]+)(https?:\/\/)(\S+\s)([\w\s]+)/i | |
| 22 | + FullCite = /([\w\s]+)(https?:\/\/)(\S+)/i | |
| 23 | + Author = /([\w\s]+)/ | |
| 24 | + | |
| 25 | + def initialize(tag_name, markup, tokens) | |
| 26 | + @by = nil | |
| 27 | + @source = nil | |
| 28 | + @title = nil | |
| 29 | + if markup =~ FullCiteWithTitle | |
| 30 | + @by = $1 | |
| 31 | + @source = $2 + $3 | |
| 32 | + @title = $4.titlecase | |
| 33 | + elsif markup =~ FullCite | |
| 34 | + @by = $1 | |
| 35 | + @source = $2 + $3 | |
| 36 | + elsif markup =~ Author | |
| 37 | + @by = $1 | |
| 38 | + end | |
| 39 | + super | |
| 40 | + end | |
| 41 | + | |
| 42 | + def render(context) | |
| 43 | + output = super | |
| 44 | + if @by.nil? | |
| 45 | + '<blockquote><p>' + output.join + '</p></blockquote>' | |
| 46 | + elsif !@title.nil? | |
| 47 | + '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + '<a class="source" href="' + @source + '">' + @title + '</a></cite></p>' | |
| 48 | + elsif !@source.nil? | |
| 49 | + '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + '<a class="source" href="' + @source + '">source</a></cite></p>' | |
| 50 | + else | |
| 51 | + '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong></cite></p>' | |
| 52 | + end | |
| 53 | + end | |
| 54 | + end | |
| 55 | + | |
| 56 | + # Outputs a string with a given attribution as a pullquote | |
| 57 | + # | |
| 58 | +  #   {% blockquote John Paul Jones %} | |
| 59 | + # Monkeys! | |
| 60 | +  #   {% endblockquote %} | |
| 61 | + # ... | |
| 62 | + # <blockquote class="pullquote"> | |
| 63 | + # Monkeys! | |
| 64 | + # <br /> | |
| 65 | + # John Paul Jones | |
| 66 | + # </blockquote> | |
| 67 | + # | |
| 68 | + class Pullquote < Liquid::Block | |
| 69 | + FullCiteWithTitle = /([\w\s]+)(http:\/\/|https:\/\/)(\S+)([\w\s]+)/i | |
| 70 | + FullCite = /([\w\s]+)(http:\/\/|https:\/\/)(\S+)/i | |
| 71 | + Author = /([\w\s]+)/ | |
| 72 | + | |
| 73 | + def initialize(tag_name, markup, tokens) | |
| 74 | + @by = nil | |
| 75 | + @source = nil | |
| 76 | + @title = nil | |
| 77 | + if markup =~ FullCiteWithTitle | |
| 78 | + @by = $1 | |
| 79 | + @source = $2 + $3 | |
| 80 | + @title = $4 | |
| 81 | + elsif markup =~ FullCite | |
| 82 | + @by = $1 | |
| 83 | + @source = $2 + $3 | |
| 84 | + elsif markup =~ Author | |
| 85 | + @by = $1 | |
| 86 | + end | |
| 87 | + super | |
| 88 | + end | |
| 89 | + | |
| 90 | + def render(context) | |
| 91 | + output = super | |
| 92 | + if @by.nil? | |
| 93 | + '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' | |
| 94 | + elsif @title | |
| 95 | + '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + ' <a class="source" href="' + @source + '">' + @title + '</a></cite></p>' | |
| 96 | + elsif @source | |
| 97 | + '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + ' <a class="source" href="' + @source + '">source</a></cite></p>' | |
| 98 | + elsif @by | |
| 99 | + '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong></cite></p>' | |
| 100 | + end | |
| 101 | + end | |
| 102 | + end | |
| 103 | +end | |
| 104 | + | |
| 105 | +Liquid::Template.register_tag('blockquote', Jekyll::Blockquote) | |
| 106 | +Liquid::Template.register_tag('pullquote', Jekyll::Pullquote) | |
| 107 | + | |
| 108 | + | 
| 0 | 109 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,65 @@ | 
| 0 | +module Jekyll | |
| 1 | + | |
| 2 | + class CategoryIndex < Page | |
| 3 | + def initialize(site, base, dir, category) | |
| 4 | + @site = site | |
| 5 | + @base = base | |
| 6 | + @dir = dir | |
| 7 | + @name = 'index.html' | |
| 8 | + | |
| 9 | + self.process(@name) | |
| 10 | + self.read_yaml(File.join(base, '_layouts'), 'category_index.html') | |
| 11 | + self.data['category'] = category | |
| 12 | + | |
| 13 | + category_title_prefix = site.config['category_title_prefix'] || 'Category: ' | |
| 14 | +      self.data['title'] = "#{category_title_prefix}#{category}" | |
| 15 | + end | |
| 16 | + end | |
| 17 | + | |
| 18 | + class CategoryList < Page | |
| 19 | + def initialize(site, base, dir, categories) | |
| 20 | + @site = site | |
| 21 | + @base = base | |
| 22 | + @dir = dir | |
| 23 | + @name = 'index.html' | |
| 24 | + | |
| 25 | + self.process(@name) | |
| 26 | + self.read_yaml(File.join(base, '_layouts'), 'category_list.html') | |
| 27 | + self.data['categories'] = categories | |
| 28 | + end | |
| 29 | + end | |
| 30 | + | |
| 31 | + class CategoryGenerator < Generator | |
| 32 | + safe true | |
| 33 | + | |
| 34 | + def generate(site) | |
| 35 | + if site.layouts.key? 'category_index' | |
| 36 | + dir = site.config['category_dir'] || 'categories' | |
| 37 | + site.categories.keys.each do |category| | |
| 38 | + write_category_index(site, File.join(dir, category.gsub(/\s/, "-").gsub(/[^\w-]/, '').downcase), category) | |
| 39 | + end | |
| 40 | + end | |
| 41 | + | |
| 42 | + if site.layouts.key? 'category_list' | |
| 43 | + dir = site.config['category_dir'] || 'categories' | |
| 44 | + write_category_list(site, dir, site.categories.keys.sort) | |
| 45 | + end | |
| 46 | + end | |
| 47 | + | |
| 48 | + def write_category_index(site, dir, category) | |
| 49 | + index = CategoryIndex.new(site, site.source, dir, category) | |
| 50 | + index.render(site.layouts, site.site_payload) | |
| 51 | + index.write(site.dest) | |
| 52 | + site.static_files << index | |
| 53 | + end | |
| 54 | + | |
| 55 | + def write_category_list(site, dir, categories) | |
| 56 | + index = CategoryList.new(site, site.source, dir, categories) | |
| 57 | + index.render(site.layouts, site.site_payload) | |
| 58 | + index.write(site.dest) | |
| 59 | + site.static_files << index | |
| 60 | + end | |
| 61 | + end | |
| 62 | + | |
| 63 | +end | |
| 64 | + | 
| 0 | 1 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,59 @@ | 
| 0 | +#custom filters for Octopress | |
| 1 | + | |
| 2 | +module OctopressFilters | |
| 3 | + def exerpt(input, url, url_text="Reade more…", permalink_text=false) | |
| 4 | + if input.index(/<!--\s?more\s?-->/i) | |
| 5 | +      input.split(/<!--\s?more\s?-->/i)[0] + "<p><a href='#{url}'>#{url_text}</a></p>" | |
| 6 | + elsif permalink_text | |
| 7 | +      input + "<p><a href='#{url}'>#{permalink_text}</a></p>" | |
| 8 | + else | |
| 9 | + input | |
| 10 | + end | |
| 11 | + end | |
| 12 | + def full_urls(input, url='') | |
| 13 | +    input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]+)/ do | |
| 14 | + $1+url+$3 | |
| 15 | + end | |
| 16 | + end | |
| 17 | + def search_url(input) | |
| 18 | + input.gsub /(http:\/\/)(\S+)/ do | |
| 19 | + $2 | |
| 20 | + end | |
| 21 | + end | |
| 22 | + def smart_quotes(input) | |
| 23 | + require 'rubypants' | |
| 24 | + RubyPants.new(input).to_html | |
| 25 | + end | |
| 26 | + def titlecase(input) | |
| 27 | + input.titlecase | |
| 28 | + end | |
| 29 | + def datetime(date) | |
| 30 | + if date.class == String | |
| 31 | + date = Time.parse(date) | |
| 32 | + end | |
| 33 | + date | |
| 34 | + end | |
| 35 | + def ordinalize(date) | |
| 36 | + date = datetime(date) | |
| 37 | +    "#{date.strftime('%B')} #{ordinal(date.strftime('%e').to_i)}, #{date.strftime('%Y')}" | |
| 38 | + end | |
| 39 | + def ordinal(number) | |
| 40 | + if (11..13).include?(number.to_i % 100) | |
| 41 | +      "#{number}<span>th</span>" | |
| 42 | + else | |
| 43 | + case number.to_i % 10 | |
| 44 | +      when 1; "#{number}<span>st</span>" | |
| 45 | +      when 2; "#{number}<span>nd<span>" | |
| 46 | +      when 3; "#{number}<span>rd</span>" | |
| 47 | +      else    "#{number}<span>th</span>" | |
| 48 | + end | |
| 49 | + end | |
| 50 | + end | |
| 51 | +  #YearlyPost = Struct.new('YearlyPost', :year, :posts) | |
| 52 | + def yearly_posts(site) | |
| 53 | +    #site.posts.reverse.group_by { |p| p.date.strftime("%Y") }.map { |k,v| YearlyPost.new(k,v) } | |
| 54 | + site | |
| 55 | + end | |
| 56 | +end | |
| 57 | +Liquid::Template.register_filter OctopressFilters | |
| 58 | + | 
| 0 | 59 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,133 @@ | 
| 0 | +# Jekyll sitemap page generator. | |
| 1 | +# http://recursive-design.com/projects/jekyll-plugins/ | |
| 2 | +# | |
| 3 | +# Version: 0.1.3 (201101061053) | |
| 4 | +# | |
| 5 | +# Copyright (c) 2010 Dave Perrett, http://recursive-design.com/ | |
| 6 | +# Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) | |
| 7 | +# | |
| 8 | +# A generator that creates a sitemap.xml page for jekyll sites, suitable for submission to | |
| 9 | +# google etc. | |
| 10 | +# | |
| 11 | +# To use it, simply drop this script into the _plugins directory of your Jekyll site. | |
| 12 | +# | |
| 13 | +# When you compile your jekyll site, this plugin will loop through the list of pages in your | |
| 14 | +# site, and generate an entry in sitemap.xml for each one. | |
| 15 | + | |
| 16 | +require 'pathname' | |
| 17 | + | |
| 18 | +module Jekyll | |
| 19 | + | |
| 20 | + | |
| 21 | + # Monkey-patch an accessor for a page's containing folder, since | |
| 22 | + # we need it to generate the sitemap. | |
| 23 | + class Page | |
| 24 | + def subfolder | |
| 25 | + @dir | |
| 26 | + end | |
| 27 | + end | |
| 28 | + | |
| 29 | + | |
| 30 | + # Sub-class Jekyll::StaticFile to allow recovery from unimportant exception | |
| 31 | + # when writing the sitemap file. | |
| 32 | + class StaticSitemapFile < StaticFile | |
| 33 | + def write(dest) | |
| 34 | + super(dest) rescue ArgumentError | |
| 35 | + true | |
| 36 | + end | |
| 37 | + end | |
| 38 | + | |
| 39 | + | |
| 40 | + # Generates a sitemap.xml file containing URLs of all pages and posts. | |
| 41 | + class SitemapGenerator < Generator | |
| 42 | + safe true | |
| 43 | + priority :low | |
| 44 | + | |
| 45 | + # Domain that you are generating the sitemap for - update this to match your site. | |
| 46 | + | |
| 47 | + # Generates the sitemap.xml file. | |
| 48 | + # | |
| 49 | + # +site+ is the global Site object. | |
| 50 | + def generate(site) | |
| 51 | + # Create the destination folder if necessary. | |
| 52 | + site_folder = site.config['destination'] | |
| 53 | + unless File.directory?(site_folder) | |
| 54 | + p = Pathname.new(site_folder) | |
| 55 | + p.mkdir | |
| 56 | + end | |
| 57 | + | |
| 58 | + # Write the contents of sitemap.xml. | |
| 59 | + File.open(File.join(site_folder, 'sitemap.xml'), 'w') do |f| | |
| 60 | + f.write(generate_header()) | |
| 61 | + f.write(generate_content(site)) | |
| 62 | + f.write(generate_footer()) | |
| 63 | + f.close | |
| 64 | + end | |
| 65 | + | |
| 66 | + # Add a static file entry for the zip file, otherwise Site::cleanup will remove it. | |
| 67 | + site.static_files << Jekyll::StaticSitemapFile.new(site, site.dest, '/', 'sitemap.xml') | |
| 68 | + end | |
| 69 | + | |
| 70 | + private | |
| 71 | + | |
| 72 | + # Returns the XML header. | |
| 73 | + def generate_header | |
| 74 | + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">" | |
| 75 | + end | |
| 76 | + | |
| 77 | + # Returns a string containing the the XML entries. | |
| 78 | + # | |
| 79 | + # +site+ is the global Site object. | |
| 80 | + def generate_content(site) | |
| 81 | + result = '' | |
| 82 | + | |
| 83 | + base_url = site.config['url'] | |
| 84 | + | |
| 85 | + # First, try to find any stand-alone pages. | |
| 86 | +      site.pages.each{ |page| | |
| 87 | + path = page.subfolder + '/' + page.name | |
| 88 | + mod_date = File.mtime(site.source + path) | |
| 89 | + | |
| 90 | + # Remove the trailing 'index.html' if there is one, and just output the folder name. | |
| 91 | + if path=~/index.html$/ | |
| 92 | + path = path[0..-11] | |
| 93 | + end | |
| 94 | + | |
| 95 | + unless path =~/error/ | |
| 96 | + result += entry(base_url, path, mod_date) | |
| 97 | + end | |
| 98 | + } | |
| 99 | + | |
| 100 | + # Next, find all the posts. | |
| 101 | + posts = site.site_payload['site']['posts'] | |
| 102 | + for post in posts do | |
| 103 | + result += entry(base_url, post.id, post.date) | |
| 104 | + end | |
| 105 | + | |
| 106 | + result | |
| 107 | + end | |
| 108 | + | |
| 109 | + # Returns the XML footer. | |
| 110 | + def generate_footer | |
| 111 | + "\n</urlset>" | |
| 112 | + end | |
| 113 | + | |
| 114 | + # Creates an XML entry from the given path and date. | |
| 115 | + # | |
| 116 | + # +path+ is the URL path to the page. | |
| 117 | + # +date+ is the date the file was modified (in the case of regular pages), or published (for blog posts). | |
| 118 | + def entry(base_url, path, date) | |
| 119 | + # Force extensions to .html from markdown, textile. | |
| 120 | + path = path.gsub(/\.(markdown|textile)$/i, '.html') | |
| 121 | + " | |
| 122 | + <url> | |
| 123 | +      <loc>#{base_url}#{path}</loc> | |
| 124 | +      <lastmod>#{date.strftime("%Y-%m-%d")}</lastmod> | |
| 125 | + </url>" | |
| 126 | + end | |
| 127 | + | |
| 128 | + end | |
| 129 | + | |
| 130 | +end | |
| 131 | + | |
| 132 | + | 
| 0 | 133 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,83 @@ | 
| 0 | +# Nicked from Brandon Tilly | |
| 1 | +# Gist https://gist.github.com/803483 | |
| 2 | +# Post http://brandontilley.com/2011/01/31/gist-tag-for-jekyll.html | |
| 3 | +# | |
| 4 | +# Example usage: {% gist 803483 gist_tag.rb %} //embeds a gist for this plugin | |
| 5 | + | |
| 6 | +require 'digest/md5' | |
| 7 | +require 'net/https' | |
| 8 | +require 'uri' | |
| 9 | + | |
| 10 | +module Jekyll | |
| 11 | + class GistTag < Liquid::Tag | |
| 12 | + def initialize(tag_name, text, token) | |
| 13 | + super | |
| 14 | +      system('mkdir -p .gist_cache') | |
| 15 | + @text = text | |
| 16 | + @cache = true | |
| 17 | + @cache_folder = File.expand_path "../.gist_cache", File.dirname(__FILE__) | |
| 18 | + end | |
| 19 | + | |
| 20 | + def render(context) | |
| 21 | + return "" unless @text =~ /([\d]*) (.*)/ | |
| 22 | + | |
| 23 | + gist, file = $1.strip, $2.strip | |
| 24 | +      script_url = "https://gist.github.com/#{gist}.js?file=#{file}" | |
| 25 | + | |
| 26 | + code = get_cached_gist(gist, file) || get_gist_from_web(gist, file) | |
| 27 | + code = code.gsub "<", "<" | |
| 28 | +      string     = "<script src='#{script_url}'></script>" | |
| 29 | +      string    += "<noscript><pre><code>#{code}</code></pre></noscript>" | |
| 30 | + return string | |
| 31 | + end | |
| 32 | + | |
| 33 | + def get_gist_url_for(gist, file) | |
| 34 | +      "https://gist.github.com/raw/#{gist}/#{file}" | |
| 35 | + end | |
| 36 | + | |
| 37 | + def cache_gist(gist, file, data) | |
| 38 | + file = get_cache_file_for gist, file | |
| 39 | + File.open(file, "w+") do |f| | |
| 40 | + f.write(data) | |
| 41 | + end | |
| 42 | + end | |
| 43 | + | |
| 44 | + def get_cached_gist(gist, file) | |
| 45 | + return nil if @cache == false | |
| 46 | + file = get_cache_file_for gist, file | |
| 47 | + return nil unless File.exist?(file) | |
| 48 | + return File.new(file).readlines.join | |
| 49 | + end | |
| 50 | + | |
| 51 | + def get_cache_file_for(gist, file) | |
| 52 | + gist.gsub! /[^a-zA-Z0-9\-_\.]/, '' | |
| 53 | + file.gsub! /[^a-zA-Z0-9\-_\.]/, '' | |
| 54 | +      md5 = Digest::MD5.hexdigest "#{gist}-#{file}" | |
| 55 | +      File.join @cache_folder, "#{gist}-#{file}-#{md5}.cache" | |
| 56 | + end | |
| 57 | + | |
| 58 | + def get_gist_from_web(gist, file) | |
| 59 | + gist_url = get_gist_url_for(gist, file) | |
| 60 | + raw_uri = URI.parse(gist_url) | |
| 61 | + https = Net::HTTP.new(raw_uri.host, raw_uri.port) | |
| 62 | + https.use_ssl = true | |
| 63 | + https.verify_mode = OpenSSL::SSL::VERIFY_NONE | |
| 64 | + request = Net::HTTP::Get.new(raw_uri.request_uri) | |
| 65 | + data = https.request(request) | |
| 66 | + data = data.body | |
| 67 | + cache_gist(gist, file, data) unless @cache == false | |
| 68 | + data | |
| 69 | + end | |
| 70 | + end | |
| 71 | + | |
| 72 | + class GistTagNoCache < GistTag | |
| 73 | + def initialize(tag_name, text, token) | |
| 74 | + super | |
| 75 | + @cache = false | |
| 76 | + end | |
| 77 | + end | |
| 78 | +end | |
| 79 | + | |
| 80 | +Liquid::Template.register_tag('gist', Jekyll::GistTag) | |
| 81 | +Liquid::Template.register_tag('gistnocache', Jekyll::GistTagNoCache) | |
| 82 | + | 
| 0 | 83 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,24 @@ | 
| 0 | +module Jekyll | |
| 1 | + require 'haml' | |
| 2 | + class HamlConverter < Converter | |
| 3 | + safe true | |
| 4 | + priority :low | |
| 5 | + | |
| 6 | + def matches(ext) | |
| 7 | + ext =~ /haml/i | |
| 8 | + end | |
| 9 | + | |
| 10 | + def output_ext(ext) | |
| 11 | + ".html" | |
| 12 | + end | |
| 13 | + | |
| 14 | + def convert(content) | |
| 15 | + begin | |
| 16 | + engine = Haml::Engine.new(content) | |
| 17 | + engine.render | |
| 18 | + rescue StandardError => e | |
| 19 | + puts "!!! HAML Error: " + e.message | |
| 20 | + end | |
| 21 | + end | |
| 22 | + end | |
| 23 | +end | 
| 0 | 24 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,49 @@ | 
| 0 | +## | |
| 1 | +## Author: Jose Gonzalez - https://github.com/josegonzalez | |
| 2 | +## Source URL: https://github.com/josegonzalez/josediazgonzalez.com/blob/master/_plugins/iterator.rb | |
| 3 | +## | |
| 4 | + | |
| 5 | +#module Jekyll | |
| 6 | + #class Site | |
| 7 | + #alias_method :orig_site_payload, :site_payload | |
| 8 | + | |
| 9 | + ## Constuct an array of hashes that will allow the user, using Liquid, to | |
| 10 | + ## iterate through the keys of _kv_hash_ and be able to iterate through the | |
| 11 | + ## elements under each key. | |
| 12 | + ## | |
| 13 | + ## Example: | |
| 14 | +    ##   categories = { 'Ruby' => [<Post>, <Post>] } | |
| 15 | + ## make_iterable(categories, :index => 'name', :items => 'posts') | |
| 16 | + ## Will allow the user to iterate through all categories and then iterate | |
| 17 | + ## though each post in the current category like so: | |
| 18 | +    ##   {% for category in site.categories %} | |
| 19 | +    ##     h1. {{ category.name }} | |
| 20 | + ## <ul> | |
| 21 | +    ##       {% for post in category.posts %} | |
| 22 | +    ##         <li>{{ post.title }}</li> | |
| 23 | +    ##       {% endfor %} | |
| 24 | + ## </ul> | |
| 25 | +    ##   {% endfor %} | |
| 26 | + ## | |
| 27 | +    ## Returns [ {<index> => <kv_hash_key>, <items> => kv_hash[<kv_hash_key>]}, ... ] | |
| 28 | + | |
| 29 | + #def make_iterable(kv_hash, options) | |
| 30 | +      #options = {:index => 'name', :items => 'items'}.merge(options) | |
| 31 | + #result = [] | |
| 32 | + #kv_hash.sort.each do |key, value| | |
| 33 | +        #result << { options[:index] => key, options[:items] => value } | |
| 34 | + #end | |
| 35 | + #result | |
| 36 | + #end | |
| 37 | + | |
| 38 | + #def site_payload | |
| 39 | + #payload = orig_site_payload | |
| 40 | +      #payload['site']['iterable'].merge!({ | |
| 41 | + #'categories' => make_iterable(self.categories, :index => 'name', :items => 'posts'), | |
| 42 | + #'tags' => make_iterable(self.tags, :index => 'name', :items => 'posts') | |
| 43 | + #}) | |
| 44 | + #payload | |
| 45 | + #end | |
| 46 | + | |
| 47 | + #end | |
| 48 | +#end | 
| 0 | 49 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,30 @@ | 
| 0 | +# | |
| 1 | +# Author: Raimonds Simanovskis, http://blog.rayapps.com/ | |
| 2 | +# Source URL: https://github.com/rsim/blog.rayapps.com/blob/master/_plugins/pygments_cache_patch.rb | |
| 3 | +# | |
| 4 | + | |
| 5 | +require 'fileutils' | |
| 6 | +require 'digest/md5' | |
| 7 | + | |
| 8 | +PYGMENTS_CACHE_DIR = File.expand_path('../../_cache', __FILE__) | |
| 9 | +FileUtils.mkdir_p(PYGMENTS_CACHE_DIR) | |
| 10 | + | |
| 11 | +Jekyll::HighlightBlock.class_eval do | |
| 12 | + def render_pygments(context, code) | |
| 13 | + if defined?(PYGMENTS_CACHE_DIR) | |
| 14 | +      path = File.join(PYGMENTS_CACHE_DIR, "#{@lang}-#{Digest::MD5.hexdigest(code)}.html") | |
| 15 | + if File.exist?(path) | |
| 16 | + highlighted_code = File.read(path) | |
| 17 | + else | |
| 18 | + highlighted_code = Albino.new(code, @lang).to_s(@options) | |
| 19 | +        File.open(path, 'w') {|f| f.print(highlighted_code) } | |
| 20 | + end | |
| 21 | + else | |
| 22 | + highlighted_code = Albino.new(code, @lang).to_s(@options) | |
| 23 | + end | |
| 24 | + output = add_code_tags(highlighted_code, @lang) | |
| 25 | + output = context["pygments_prefix"] + output if context["pygments_prefix"] | |
| 26 | + output = output + context["pygments_suffix"] if context["pygments_suffix"] | |
| 27 | + output | |
| 28 | + end | |
| 29 | +end | 
| 0 | 30 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,309 @@ | 
| 0 | +# Sitemap.xml Generator is a Jekyll plugin that generates a sitemap.xml file by | |
| 1 | +# traversing all of the available posts and pages. | |
| 2 | +# | |
| 3 | +# How To Use: | |
| 4 | +# 1.) Copy source file into your _plugins folder within your Jekyll project. | |
| 5 | +# 2.) Change MY_URL to reflect your domain name. | |
| 6 | +# 3.) Change SITEMAP_FILE_NAME if you want your sitemap to be called something | |
| 7 | +# other than sitemap.xml. | |
| 8 | +# 4.) Change the PAGES_INCLUDE_POSTS list to include any pages that are looping | |
| 9 | +# through your posts (e.g. "index.html", "archive.html", etc.). This will | |
| 10 | +# ensure that right after you make a new post, the last modified date will | |
| 11 | +# be updated to reflect the new post. | |
| 12 | +# 5.) Run Jekyll: jekyll --server to re-generate your site. | |
| 13 | +# 6.) A sitemap.xml should be included in your _site folder. | |
| 14 | +# | |
| 15 | +# Customizations: | |
| 16 | +# 1.) If there are any files you don't want included in the sitemap, add them | |
| 17 | +# to the EXCLUDED_FILES list. The name should match the name of the source | |
| 18 | +# file. | |
| 19 | +# 2.) If you want to include the optional changefreq and priority attributes, | |
| 20 | +# simply include custom variables in the YAML Front Matter of that file. | |
| 21 | +# The names of these custom variables are defined below in the | |
| 22 | +# CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME and PRIORITY_CUSTOM_VARIABLE_NAME | |
| 23 | +# constants. | |
| 24 | +# | |
| 25 | +# Notes: | |
| 26 | +# 1.) The last modified date is determined by the latest from the following: | |
| 27 | +# system modified date of the page or post, system modified date of | |
| 28 | +# included layout, system modified date of included layout within that | |
| 29 | +# layout, ... | |
| 30 | +# | |
| 31 | +# Author: Michael Levin | |
| 32 | +# Site: http://www.kinnetica.com | |
| 33 | +# Distributed Under A Creative Commons License | |
| 34 | +# - http://creativecommons.org/licenses/by/3.0/ | |
| 35 | + | |
| 36 | +require 'rexml/document' | |
| 37 | + | |
| 38 | +module Jekyll | |
| 39 | + | |
| 40 | + # Change MY_URL to reflect the site you are using | |
| 41 | + MY_URL = "http://www.mysite.com" | |
| 42 | + | |
| 43 | + # Change SITEMAP_FILE_NAME if you would like your sitemap file | |
| 44 | + # to be called something else | |
| 45 | + SITEMAP_FILE_NAME = "sitemap.xml" | |
| 46 | + | |
| 47 | + # Any files to exclude from being included in the sitemap.xml | |
| 48 | + EXCLUDED_FILES = ["atom.xml"] | |
| 49 | + | |
| 50 | + # Any files that include posts, so that when a new post is added, the last | |
| 51 | + # modified date of these pages should take that into account | |
| 52 | + PAGES_INCLUDE_POSTS = ["index.html"] | |
| 53 | + | |
| 54 | + # Custom variable names for changefreq and priority elements | |
| 55 | + # These names are used within the YAML Front Matter of pages or posts | |
| 56 | + # for which you want to include these properties | |
| 57 | + CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME = "change_frequency" | |
| 58 | + PRIORITY_CUSTOM_VARIABLE_NAME = "priority" | |
| 59 | + | |
| 60 | + class Post | |
| 61 | + attr_accessor :name | |
| 62 | + | |
| 63 | + def full_path_to_source | |
| 64 | + File.join(@base, @name) | |
| 65 | + end | |
| 66 | + | |
| 67 | + def location_on_server | |
| 68 | +      "#{MY_URL}#{url}" | |
| 69 | + end | |
| 70 | + end | |
| 71 | + | |
| 72 | + class Page | |
| 73 | + attr_accessor :name | |
| 74 | + | |
| 75 | + def full_path_to_source | |
| 76 | + File.join(@base, @dir, @name) | |
| 77 | + end | |
| 78 | + | |
| 79 | + def location_on_server | |
| 80 | +      location = "#{MY_URL}#{@dir}#{url}" | |
| 81 | + location.gsub(/index.html$/, "") | |
| 82 | + end | |
| 83 | + end | |
| 84 | + | |
| 85 | + class Layout | |
| 86 | + def full_path_to_source | |
| 87 | + File.join(@base, @name) | |
| 88 | + end | |
| 89 | + end | |
| 90 | + | |
| 91 | + # Recover from strange exception when starting server without --auto | |
| 92 | + class SitemapFile < StaticFile | |
| 93 | + def write(dest) | |
| 94 | + begin | |
| 95 | + super(dest) | |
| 96 | + rescue | |
| 97 | + end | |
| 98 | + | |
| 99 | + true | |
| 100 | + end | |
| 101 | + end | |
| 102 | + | |
| 103 | + class SitemapGenerator < Generator | |
| 104 | + | |
| 105 | + # Valid values allowed by sitemap.xml spec for change frequencies | |
| 106 | + VALID_CHANGE_FREQUENCY_VALUES = ["always", "hourly", "daily", "weekly", | |
| 107 | + "monthly", "yearly", "never"] | |
| 108 | + | |
| 109 | + # Goes through pages and posts and generates sitemap.xml file | |
| 110 | + # | |
| 111 | + # Returns nothing | |
| 112 | + def generate(site) | |
| 113 | +      sitemap = REXML::Document.new << REXML::XMLDecl.new("1.0", "UTF-8") | |
| 114 | + | |
| 115 | + urlset = REXML::Element.new "urlset" | |
| 116 | +      urlset.add_attribute("xmlns", | |
| 117 | + "http://www.sitemaps.org/schemas/sitemap/0.9") | |
| 118 | + | |
| 119 | + @last_modified_post_date = fill_posts(site, urlset) | |
| 120 | + fill_pages(site, urlset) | |
| 121 | + | |
| 122 | + sitemap.add_element(urlset) | |
| 123 | + | |
| 124 | + # File I/O: create sitemap.xml file and write out pretty-printed XML | |
| 125 | + file = File.new(File.join(site.dest, SITEMAP_FILE_NAME), "w") | |
| 126 | + formatter = REXML::Formatters::Pretty.new(4) | |
| 127 | + formatter.compact = true | |
| 128 | + formatter.write(sitemap, file) | |
| 129 | + file.close | |
| 130 | + | |
| 131 | + # Keep the sitemap.xml file from being cleaned by Jekyll | |
| 132 | + site.static_files << Jekyll::SitemapFile.new(site, site.dest, "/", SITEMAP_FILE_NAME) | |
| 133 | + end | |
| 134 | + | |
| 135 | + # Create url elements for all the posts and find the date of the latest one | |
| 136 | + # | |
| 137 | + # Returns last_modified_date of latest post | |
| 138 | + def fill_posts(site, urlset) | |
| 139 | + last_modified_date = nil | |
| 140 | + site.posts.each do |post| | |
| 141 | + if !excluded?(post.name) | |
| 142 | + url = fill_url(site, post) | |
| 143 | + urlset.add_element(url) | |
| 144 | + end | |
| 145 | + | |
| 146 | + path = post.full_path_to_source | |
| 147 | + date = File.mtime(path) | |
| 148 | + last_modified_date = date if last_modified_date == nil or date > last_modified_date | |
| 149 | + end | |
| 150 | + | |
| 151 | + last_modified_date | |
| 152 | + end | |
| 153 | + | |
| 154 | + # Create url elements for all the normal pages and find the date of the | |
| 155 | + # index to use with the pagination pages | |
| 156 | + # | |
| 157 | + # Returns last_modified_date of index page | |
| 158 | + def fill_pages(site, urlset) | |
| 159 | + site.pages.each do |page| | |
| 160 | + if !excluded?(page.name) | |
| 161 | + path = page.full_path_to_source | |
| 162 | + if File.exists?(path) | |
| 163 | + url = fill_url(site, page) | |
| 164 | + urlset.add_element(url) | |
| 165 | + end | |
| 166 | + end | |
| 167 | + end | |
| 168 | + end | |
| 169 | + | |
| 170 | + # Fill data of each URL element: location, last modified, | |
| 171 | + # change frequency (optional), and priority. | |
| 172 | + # | |
| 173 | + # Returns url REXML::Element | |
| 174 | + def fill_url(site, page_or_post) | |
| 175 | + url = REXML::Element.new "url" | |
| 176 | + | |
| 177 | + loc = fill_location(page_or_post) | |
| 178 | + url.add_element(loc) | |
| 179 | + | |
| 180 | + lastmod = fill_last_modified(site, page_or_post) | |
| 181 | + url.add_element(lastmod) if lastmod | |
| 182 | + | |
| 183 | + if (page_or_post.data[CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME]) | |
| 184 | + change_frequency = | |
| 185 | + page_or_post.data[CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME].downcase | |
| 186 | + | |
| 187 | + if (valid_change_frequency?(change_frequency)) | |
| 188 | + changefreq = REXML::Element.new "changefreq" | |
| 189 | + changefreq.text = change_frequency | |
| 190 | + url.add_element(changefreq) | |
| 191 | + else | |
| 192 | +          puts "ERROR: Invalid Change Frequency In #{page_or_post.name}" | |
| 193 | + end | |
| 194 | + end | |
| 195 | + | |
| 196 | + if (page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME]) | |
| 197 | + priority_value = page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME] | |
| 198 | + if valid_priority?(priority_value) | |
| 199 | + priority = REXML::Element.new "priority" | |
| 200 | + priority.text = page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME] | |
| 201 | + url.add_element(priority) | |
| 202 | + else | |
| 203 | +          puts "ERROR: Invalid Priority In #{page_or_post.name}" | |
| 204 | + end | |
| 205 | + end | |
| 206 | + | |
| 207 | + url | |
| 208 | + end | |
| 209 | + | |
| 210 | + # Get URL location of page or post | |
| 211 | + # | |
| 212 | + # Returns the location of the page or post | |
| 213 | + def fill_location(page_or_post) | |
| 214 | + loc = REXML::Element.new "loc" | |
| 215 | + loc.text = page_or_post.location_on_server | |
| 216 | + | |
| 217 | + loc | |
| 218 | + end | |
| 219 | + | |
| 220 | + # Fill lastmod XML element with the last modified date for the page or post. | |
| 221 | + # | |
| 222 | + # Returns lastmod REXML::Element or nil | |
| 223 | + def fill_last_modified(site, page_or_post) | |
| 224 | + path = page_or_post.full_path_to_source | |
| 225 | + | |
| 226 | + lastmod = REXML::Element.new "lastmod" | |
| 227 | + date = File.mtime(path) | |
| 228 | + latest_date = find_latest_date(date, site, page_or_post) | |
| 229 | + | |
| 230 | + if @last_modified_post_date == nil | |
| 231 | + # This is a post | |
| 232 | + lastmod.text = latest_date.iso8601 | |
| 233 | + else | |
| 234 | + # This is a page | |
| 235 | + if posts_included?(page_or_post.name) | |
| 236 | + # We want to take into account the last post date | |
| 237 | + final_date = greater_date(latest_date, @last_modified_post_date) | |
| 238 | + lastmod.text = final_date.iso8601 | |
| 239 | + else | |
| 240 | + lastmod.text = latest_date.iso8601 | |
| 241 | + end | |
| 242 | + end | |
| 243 | + lastmod | |
| 244 | + end | |
| 245 | + | |
| 246 | + # Go through the page/post and any implemented layouts and get the latest | |
| 247 | + # modified date | |
| 248 | + # | |
| 249 | + # Returns formatted output of latest date of page/post and any used layouts | |
| 250 | + def find_latest_date(latest_date, site, page_or_post) | |
| 251 | + layouts = site.layouts | |
| 252 | + layout = layouts[page_or_post.data["layout"]] | |
| 253 | + while layout | |
| 254 | + path = layout.full_path_to_source | |
| 255 | + date = File.mtime(path) | |
| 256 | + | |
| 257 | + latest_date = date if (date > latest_date) | |
| 258 | + | |
| 259 | + layout = layouts[layout.data["layout"]] | |
| 260 | + end | |
| 261 | + | |
| 262 | + latest_date | |
| 263 | + end | |
| 264 | + | |
| 265 | + # Which of the two dates is later | |
| 266 | + # | |
| 267 | + # Returns latest of two dates | |
| 268 | + def greater_date(date1, date2) | |
| 269 | + if (date1 >= date2) | |
| 270 | + date1 | |
| 271 | + else | |
| 272 | + date2 | |
| 273 | + end | |
| 274 | + end | |
| 275 | + | |
| 276 | + # Is the page or post listed as something we want to exclude? | |
| 277 | + # | |
| 278 | + # Returns boolean | |
| 279 | + def excluded?(name) | |
| 280 | + EXCLUDED_FILES.include? name | |
| 281 | + end | |
| 282 | + | |
| 283 | + def posts_included?(name) | |
| 284 | + PAGES_INCLUDE_POSTS.include? name | |
| 285 | + end | |
| 286 | + | |
| 287 | + # Is the change frequency value provided valid according to the spec | |
| 288 | + # | |
| 289 | + # Returns boolean | |
| 290 | + def valid_change_frequency?(change_frequency) | |
| 291 | + VALID_CHANGE_FREQUENCY_VALUES.include? change_frequency | |
| 292 | + end | |
| 293 | + | |
| 294 | + # Is the priority value provided valid according to the spec | |
| 295 | + # | |
| 296 | + # Returns boolean | |
| 297 | + def valid_priority?(priority) | |
| 298 | + begin | |
| 299 | + priority_val = Float(priority) | |
| 300 | + return true if priority_val >= 0.0 and priority_val <= 1.0 | |
| 301 | + rescue ArgumentError | |
| 302 | + end | |
| 303 | + | |
| 304 | + false | |
| 305 | + end | |
| 306 | + end | |
| 307 | +end | |
| 308 | + | 
| 0 | 309 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,36 @@ | 
| 0 | +class String | |
| 1 | + def titlecase | |
| 2 | + small_words = %w(a an and as at but by en for if in of on or the to v v. via vs vs.) | |
| 3 | + | |
| 4 | +    x = split(" ").map do |word| | |
| 5 | + # note: word could contain non-word characters! | |
| 6 | + # downcase all small_words, capitalize the rest | |
| 7 | + small_words.include?(word.gsub(/\W/, "").downcase) ? word.downcase! : word.smart_capitalize! | |
| 8 | + word | |
| 9 | + end | |
| 10 | + # capitalize first and last words | |
| 11 | + x.first.to_s.smart_capitalize! | |
| 12 | + x.last.to_s.smart_capitalize! | |
| 13 | + # small words after colons are capitalized | |
| 14 | +    x.join(" ").gsub(/:\s?(\W*#{small_words.join("|")}\W*)\s/) { ": #{$1.smart_capitalize} " } | |
| 15 | + end | |
| 16 | + | |
| 17 | + def titlecase! | |
| 18 | + replace(titlecase) | |
| 19 | + end | |
| 20 | + | |
| 21 | + def smart_capitalize | |
| 22 | + # ignore any leading crazy characters and capitalize the first real character | |
| 23 | + if self =~ /^['"\(\[']*([a-z])/ | |
| 24 | + i = index($1) | |
| 25 | + x = self[i,self.length] | |
| 26 | + # word with capitals and periods mid-word are left alone | |
| 27 | + self[i,1] = self[i,1].upcase unless x =~ /[A-Z]/ or x =~ /\.\w+/ | |
| 28 | + end | |
| 29 | + self | |
| 30 | + end | |
| 31 | + | |
| 32 | + def smart_capitalize! | |
| 33 | + replace(smart_capitalize) | |
| 34 | + end | |
| 35 | +end |