1
0
mirror of https://github.com/kremalicious/blog.git synced 2024-11-13 16:45:14 +01:00

titlecase, rubypants for post content, more stuff from octopress

This commit is contained in:
Matthias Kretschmann 2013-12-01 18:23:11 +01:00
parent 1c522f648f
commit 82e9d7e45b
12 changed files with 392 additions and 35 deletions

View File

@ -4,4 +4,6 @@ source "https://rubygems.org"
# gem "rails"
gem 'jekyll', '~>1.3.0'
gem 'mini_magick', '~>3.6.0'
gem 'fileutils', '~>0.7'
gem 'fileutils', '~>0.7'
gem 'rubypants', '~> 0.2.0'
gem 'gsl', '~> 1.15.3'

View File

@ -10,6 +10,8 @@ GEM
ffi (1.9.3)
fileutils (0.7)
rmagick (>= 2.13.1)
gsl (1.15.3)
narray (>= 0.5.9)
highline (1.6.20)
jekyll (1.3.1)
classifier (~> 1.3)
@ -30,6 +32,7 @@ GEM
syntax (>= 1.0.0)
mini_magick (3.6.0)
subexec (~> 0.2.1)
narray (0.6.0.8)
posix-spawn (0.3.6)
pygments.rb (0.5.4)
posix-spawn (~> 0.3.6)
@ -41,6 +44,7 @@ GEM
ffi (>= 0.5.0)
redcarpet (2.3.0)
rmagick (2.13.2)
rubypants (0.2.0)
safe_yaml (0.9.7)
subexec (0.2.3)
syntax (1.0.0)
@ -51,5 +55,7 @@ PLATFORMS
DEPENDENCIES
fileutils (~> 0.7)
gsl (~> 1.15.3)
jekyll (~> 1.3.0)
mini_magick (~> 3.6.0)
rubypants (~> 0.2.0)

View File

@ -5,7 +5,7 @@
<header>
<h1 class="entry-title">
<a href="{{ post.linkurl }}" title="Go to source: {{ post.linkurl | remove:'http://' | remove:'https://' | remove:'www.' }}">
{{ post.title }} <i class="icon-forward"></i>
{{ post.title | titlecase }} <i class="icon-forward"></i>
<span class="linkurl">{{ post.linkurl | remove:'http://' | remove:'https://' | remove:'www.' | split:'/' | first }}</span>
</a>
</h1>
@ -29,7 +29,7 @@
{% picture {{ post.image }} %}
<figcaption class="entry-title fn">{{ post.title }}</figcaption>
<figcaption class="entry-title fn">{{ post.title | titlecase }}</figcaption>
</figure>
</a>
@ -39,7 +39,7 @@
<article class="hentry format-post">
<header>
<h1 class="entry-title"><a href="{{ post.url }}">{{ post.title }}</a></h1>
<h1 class="entry-title"><a href="{{ post.url }}">{{ post.title | titlecase }}</a></h1>
</header>
<section class="entry-content">

View File

@ -17,7 +17,7 @@ layout: base
<article class="hentry goodie">
<header>
<h1 class="entry-title"><a href="{{ post.url }}">{{ post.title }}</a></h1>
<h1 class="entry-title"><a href="{{ post.url }}">{{ post.title | titlecase }}</a></h1>
</header>
<section class="entry-content">
@ -35,7 +35,7 @@ layout: base
<p class="info col3">
<a class="btn icon-info" href="{{ post.url }}">Release Post</a>
</p>
{% if post.download %}
<p class="download col3">
<a class="btn icon-arrow-down" href="/media/{{ post.download }}">Download <span>zip</span></a>
@ -57,4 +57,6 @@ layout: base
</div>
{% endif %}
</section>
</section>
{% include paginator.html %}

View File

@ -8,7 +8,7 @@ layout: base
<header>
<h1 class="entry-title">
<a href="{{ post.linkurl }}" title="Go to source: {{ page.linkurl | remove:'http://' | remove:'https://' | remove:'www.' }}">
{{ page.title }} <i class="icon-forward"></i>
{{ page.title | titlecase }} <i class="icon-forward"></i>
<span class="linkurl">{{ page.linkurl | remove:'http://' | remove:'https://' | remove:'www.' | split:'/' | first }}</span>
</a>
</h1>

View File

@ -10,7 +10,7 @@ layout: base
{% picture {{ page.image }} %}
<figcaption class="entry-title fn">{{ page.title }}</figcaption>
<figcaption class="entry-title fn">{{ page.title | titlecase }}</figcaption>
</figure>

View File

@ -6,7 +6,7 @@ layout: base
<article class="hentry format-post">
<header>
<h1 class="entry-title">{{ page.title }}</h1>
<h1 class="entry-title">{{ page.title | titlecase }}</h1>
</header>
<section class="entry-content">
@ -14,7 +14,7 @@ layout: base
{% picture {{ page.image }} class="teaser" %}
{% endif %}
{{ content }}
{{ content | condense_spaces }}
</section>
{% include entry_meta.html %}

View File

@ -1,32 +1,127 @@
# Filters taken from the Octopress project by Brandon Mathis.
# https://github.com/imathis/octopress/blob/master/plugins/octopress_filters.rb
#custom filters for Octopress
require './_src/_plugins/post_filters.rb'
require './_src/_plugins/raw.rb'
require 'rubypants'
module OctopressFilters
include TemplateWrapper
def pre_filter(input)
input = input
end
def post_filter(input)
input = unwrap(input)
RubyPants.new(input).to_html
end
end
module Jekyll
module Filters
# Used on the blog index to split posts on the <!--more--> marker
def excerpt(input)
if input.index(/<!--\s*more\s*-->/i)
input.split(/<!--\s*more\s*-->/i)[0]
else
input
class ContentFilters < PostFilter
include OctopressFilters
def pre_render(post)
if post.ext.match('html|textile|markdown|md|haml|slim|xml')
post.content = pre_filter(post.content)
end
end
# Checks for excerpts (helpful for template conditionals)
def has_more(input)
input =~ /<!--\s*more\s*-->/i ? true : false
end
# Replaces relative urls with full urls
def expand_urls(input, url='')
url ||= '/'
input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]*)/ do
$1+url+$3
def post_render(post)
if post.ext.match('html|textile|markdown|md|haml|slim|xml')
post.content = post_filter(post.content)
end
end
end
end
module OctopressLiquidFilters
# Used on the blog index to split posts on the <!--more--> marker
def excerpt(input)
if input.index(/<!--\s*more\s*-->/i)
input.split(/<!--\s*more\s*-->/i)[0]
else
input
end
end
# Checks for excerpts (helpful for template conditionals)
def has_excerpt(input)
input =~ /<!--\s*more\s*-->/i ? true : false
end
# Summary is used on the Archive pages to return the first block of content from a post.
def summary(input)
if input.index(/\n\n/)
input.split(/\n\n/)[0]
else
input
end
end
# Extracts raw content DIV from template, used for page description as {{ content }}
# contains complete sub-template code on main page level
def raw_content(input)
/<div class="entry-content">(?<content>[\s\S]*?)<\/div>\s*<(footer|\/article)>/ =~ input
return (content.nil?) ? input : content
end
# Escapes CDATA sections in post content
def cdata_escape(input)
input.gsub(/<!\[CDATA\[/, '&lt;![CDATA[').gsub(/\]\]>/, ']]&gt;')
end
# Replaces relative urls with full urls
def expand_urls(input, url='')
url ||= '/'
input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]*)/ do
$1+url+$3
end
end
# Improved version of Liquid's truncate:
# - Doesn't cut in the middle of a word.
# - Uses typographically correct ellipsis (…) insted of '...'
def truncate(input, length)
if input.length > length && input[0..(length-1)] =~ /(.+)\b.+$/im
$1.strip + ' &hellip;'
else
input
end
end
# Improved version of Liquid's truncatewords:
# - Uses typographically correct ellipsis (…) insted of '...'
def truncatewords(input, length)
truncate = input.split(' ')
if truncate.length > length
truncate[0..length-1].join(' ').strip + ' &hellip;'
else
input
end
end
# Condenses multiple spaces and tabs into a single space
def condense_spaces(input)
input.gsub(/\s{2,}/, ' ')
end
# Removes trailing forward slash from a string for easily appending url segments
def strip_slash(input)
if input =~ /(.+)\/$|^\/$/
input = $1
end
input
end
# Returns a url without the protocol (http://)
def shorthand_url(input)
input.gsub /(https?:\/\/)(\S+)/ do
$2
end
end
# Returns a title cased string based on John Gruber's title case http://daringfireball.net/2008/08/title_case_update
def titlecase(input)
input.titlecase
end
end
Liquid::Template.register_filter(Jekyll::Filters)
Liquid::Template.register_filter OctopressLiquidFilters

View File

@ -0,0 +1,176 @@
module Jekyll
# Extended plugin type that allows the plugin
# to be called on varous callback methods.
#
# Examples:
# https://github.com/tedkulp/octopress/blob/master/plugins/post_metaweblog.rb
# https://github.com/tedkulp/octopress/blob/master/plugins/post_twitter.rb
class PostFilter < Plugin
#Called before post is sent to the converter. Allows
#you to modify the post object before the converter
#does it's thing
def pre_render(post)
end
#Called after the post is rendered with the converter.
#Use the post object to modify it's contents before the
#post is inserted into the template.
def post_render(post)
end
#Called after the post is written to the disk.
#Use the post object to read it's contents to do something
#after the post is safely written.
def post_write(post)
end
end
# Monkey patch for the Jekyll Site class. For the original class,
# see: https://github.com/mojombo/jekyll/blob/master/lib/jekyll/site.rb
class Site
# Instance variable to store the various post_filter
# plugins that are loaded.
attr_accessor :post_filters
# Instantiates all of the post_filter plugins. This is basically
# a duplication of the other loaders in Site#setup.
def load_post_filters
self.post_filters = Jekyll::PostFilter.subclasses.select do |c|
!self.safe || c.safe
end.map do |c|
c.new(self.config)
end
end
end
# Monkey patch for the Jekyll Post class. For the original class,
# see: https://github.com/mojombo/jekyll/blob/master/lib/jekyll/post.rb
class Post
# Copy the #write method to #old_write, so we can redefine #write
# method.
alias_method :old_write, :write
# Write the generated post file to the destination directory. It
# then calls any post_write methods that may exist.
# +dest+ is the String path to the destination dir
#
# Returns nothing
def write(dest)
old_write(dest)
post_write if respond_to?(:post_write)
end
end
# Monkey patch for the Jekyll Page class. For the original class,
# see: https://github.com/mojombo/jekyll/blob/master/lib/jekyll/page.rb
class Page
# Copy the #write method to #old_write, so we can redefine #write
# method.
alias_method :old_write, :write
# Write the generated post file to the destination directory. It
# then calls any post_write methods that may exist.
# +dest+ is the String path to the destination dir
#
# Returns nothing
def write(dest)
old_write(dest)
post_write if respond_to?(:post_write)
end
end
# Monkey patch for the Jekyll Convertible module. For the original class,
# see: https://github.com/mojombo/jekyll/blob/master/lib/jekyll/convertible.rb
module Convertible
def is_post?
self.class.to_s == 'Jekyll::Post'
end
def is_page?
self.class.to_s == 'Jekyll::Page'
end
def is_filterable?
is_post? or is_page?
end
# Call the #pre_render methods on all of the loaded
# post_filter plugins.
#
# Returns nothing
def pre_render
self.site.load_post_filters unless self.site.post_filters
if self.site.post_filters and is_filterable?
self.site.post_filters.each do |filter|
filter.pre_render(self)
end
end
end
# Call the #post_render methods on all of the loaded
# post_filter plugins.
#
# Returns nothing
def post_render
if self.site.post_filters and is_filterable?
self.site.post_filters.each do |filter|
filter.post_render(self)
end
end
end
# Call the #post_write methods on all of the loaded
# post_filter plugins.
#
# Returns nothing
def post_write
if self.site.post_filters and is_filterable?
self.site.post_filters.each do |filter|
filter.post_write(self)
end
end
end
# Copy the #transform method to #old_transform, so we can
# redefine #transform method.
alias_method :old_transform, :transform
# Transform the contents based on the content type. Then calls the
# #post_render method if it exists
#
# Returns nothing.
def transform
old_transform
post_render if respond_to?(:post_render)
end
# Copy the #do_layout method to #old_do_layout, so we can
# redefine #do_layout method.
alias_method :old_do_layout, :do_layout
# Calls the pre_render method if it exists and then adds any necessary
# layouts to this convertible document.
#
# payload - The site payload Hash.
# layouts - A Hash of {"name" => "layout"}.
#
# Returns nothing.
def do_layout(payload, layouts)
pre_render if respond_to?(:pre_render)
old_do_layout(payload, layouts)
end
# Returns the full url of the post, including the
# configured url
def full_url
self.site.config['url'] + self.url
end
end
end

40
_src/_plugins/raw.rb Normal file
View File

@ -0,0 +1,40 @@
# Author: Brandon Mathis
# Description: Provides plugins with a method for wrapping and unwrapping input to prevent Markdown and Textile from parsing it.
# Purpose: This is useful for preventing Markdown and Textile from being too aggressive and incorrectly parsing in-line HTML.
module TemplateWrapper
# Wrap input with a <div>
def safe_wrap(input)
"<div class='bogus-wrapper'><notextile>#{input}</notextile></div>"
end
# This must be applied after the
def unwrap(input)
input.gsub /<div class='bogus-wrapper'><notextile>(.+?)<\/notextile><\/div>/m do
$1
end
end
end
# Author: phaer, https://github.com/phaer
# Source: https://gist.github.com/1020852
# Description: Raw tag for jekyll. Keeps liquid from parsing text betweeen {% raw %} and {% endraw %}
module Jekyll
class RawTag < Liquid::Block
def parse(tokens)
@nodelist ||= []
@nodelist.clear
while token = tokens.shift
if token =~ FullToken
if block_delimiter == $1
end_tag
return
end
end
@nodelist << token if not token.empty?
end
end
end
end
Liquid::Template.register_tag('raw', Jekyll::RawTag)

View File

@ -0,0 +1,36 @@
class String
def titlecase
small_words = %w(a an and as at but by en for if in of on or the to v v. via vs vs. ezeep)
x = split(" ").map do |word|
# note: word could contain non-word characters!
# downcase all small_words, capitalize the rest
small_words.include?(word.gsub(/\W/, "").downcase) ? word.downcase! : word.smart_capitalize!
word
end
# capitalize first and last words
#x.first.to_s.smart_capitalize!
#x.last.to_s.smart_capitalize!
# small words are capitalized after colon, period, exclamation mark, question mark
x.join(" ").gsub(/(:|\.|!|\?)\s?(\W*#{small_words.join("|")}\W*)\s/) { "#{$1} #{$2.smart_capitalize} " }
end
def titlecase!
replace(titlecase)
end
def smart_capitalize
# ignore any leading crazy characters and capitalize the first real character
if self =~ /^['"\(\[']*([a-z])/
i = index($1)
x = self[i,self.length]
# word with capitals and periods mid-word are left alone
self[i,1] = self[i,1].upcase unless x =~ /[A-Z]/ or x =~ /\.\w+/
end
self
end
def smart_capitalize!
replace(smart_capitalize)
end
end

View File

@ -3,7 +3,7 @@
[
{% for post in site.posts %}
{
"title" : "{{ post.title | escape }}",
"title" : "{{ post.title | escape | titlecase }}",
"category" : "{{ post.categories }}",
"url" : "{{ post.url }}",
"date" : "{{ post.date }}",