... | ... |
@@ -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 |