henshin 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -1
- data/README.markdown +0 -1
- data/Rakefile +4 -1
- data/VERSION +1 -1
- data/bin/files.rb +46 -0
- data/bin/henshin +47 -79
- data/henshin.gemspec +37 -14
- data/lib/henshin.rb +50 -36
- data/lib/henshin/archive.rb +161 -0
- data/lib/henshin/categories.rb +6 -1
- data/lib/henshin/ext.rb +2 -53
- data/lib/henshin/gen.rb +16 -15
- data/lib/henshin/plugin.rb +20 -7
- data/lib/henshin/plugins/highlight.rb +31 -0
- data/lib/henshin/plugins/liquid.rb +48 -14
- data/lib/henshin/plugins/maruku.rb +3 -4
- data/lib/henshin/plugins/sass.rb +7 -6
- data/lib/henshin/plugins/textile.rb +3 -4
- data/lib/henshin/post.rb +50 -8
- data/lib/henshin/site.rb +60 -34
- data/lib/henshin/tags.rb +5 -1
- data/test/site/css/{print.sass → includes/reset.sass} +0 -3
- data/test/site/css/{screen.css → print.css} +1 -4
- data/test/site/css/screen.sass +70 -0
- data/test/site/includes/head.html +1 -0
- data/test/site/index.html +12 -2
- data/test/site/layouts/archive_date.html +19 -0
- data/test/site/layouts/archive_month.html +19 -0
- data/test/site/layouts/archive_year.html +19 -0
- data/test/site/layouts/category_index.html +5 -4
- data/test/site/layouts/category_page.html +2 -2
- data/test/site/layouts/main.html +1 -36
- data/test/site/layouts/post.html +15 -5
- data/test/site/layouts/tag_index.html +3 -3
- data/test/site/layouts/tag_page.html +2 -2
- data/test/site/options.yaml +7 -4
- data/test/site/posts/Testing-Stuff.markdown +7 -1
- data/test/test_archives.rb +27 -0
- data/test/test_categories.rb +0 -0
- data/test/test_gens.rb +28 -7
- data/test/test_options.rb +4 -2
- data/test/test_posts.rb +50 -14
- data/test/test_site.rb +55 -7
- data/test/test_statics.rb +0 -0
- data/test/test_tags.rb +0 -0
- data/test/text_exts.rb +0 -0
- metadata +86 -17
- data/lib/henshin/plugins/pygments.rb +0 -17
@@ -0,0 +1,161 @@
|
|
1
|
+
module Henshin
|
2
|
+
|
3
|
+
class Archive
|
4
|
+
|
5
|
+
attr_accessor :config
|
6
|
+
|
7
|
+
def initialize( site )
|
8
|
+
@archive = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = []} }}
|
9
|
+
@site = site
|
10
|
+
@config = site.config
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_post( post )
|
14
|
+
date = post.date
|
15
|
+
@archive[date.year.to_s][date.month.to_s][date.day.to_s] << post.to_hash
|
16
|
+
end
|
17
|
+
|
18
|
+
# Turns the whole archive into a hash. Probably the least efficient thing in the world, but it works
|
19
|
+
def to_hash
|
20
|
+
if @hashed
|
21
|
+
@hashed
|
22
|
+
else
|
23
|
+
@hashed = Hash.new do |h, k|
|
24
|
+
h[k] = Hash.new do |h, k| # years
|
25
|
+
if k == 'posts'
|
26
|
+
h[k] = []
|
27
|
+
else
|
28
|
+
h[k] = Hash.new do |h, k| # months
|
29
|
+
if k == 'posts'
|
30
|
+
h[k] = []
|
31
|
+
else
|
32
|
+
h[k] = Hash.new do |h, k| # days
|
33
|
+
if k == 'posts'
|
34
|
+
h[k] = []
|
35
|
+
else
|
36
|
+
h[k] = {}
|
37
|
+
end
|
38
|
+
end # /days
|
39
|
+
end
|
40
|
+
end # /months
|
41
|
+
end
|
42
|
+
end # /years
|
43
|
+
end
|
44
|
+
@archive.each do |y, month|
|
45
|
+
month.each do |m, date|
|
46
|
+
date.each do |d, p|
|
47
|
+
@hashed[y]['posts'] << p
|
48
|
+
@hashed[y][m]['posts'] << p
|
49
|
+
@hashed[y][m][d]['posts'] << p
|
50
|
+
|
51
|
+
@hashed[y]['posts'].flatten!
|
52
|
+
@hashed[y][m]['posts'].flatten!
|
53
|
+
@hashed[y][m][d]['posts'].flatten!
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Creates a hash with posts separated by year, month then date
|
62
|
+
def to_date_hash
|
63
|
+
r = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = []} }}
|
64
|
+
@archive.each do |year, m|
|
65
|
+
m.each do |month, d|
|
66
|
+
d.each do |date, p|
|
67
|
+
r[year][month][date] << p
|
68
|
+
r[year][month][date].flatten!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
r
|
73
|
+
end
|
74
|
+
|
75
|
+
# Creates a hash with posts separated by year then month
|
76
|
+
def to_month_hash
|
77
|
+
r = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = []} }
|
78
|
+
@archive.each do |year, m|
|
79
|
+
m.each do |month, d|
|
80
|
+
d.each do |date, p|
|
81
|
+
r[year][month] << p
|
82
|
+
r[year][month].flatten!
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
r
|
87
|
+
end
|
88
|
+
|
89
|
+
# Creates a hash with posts separated by year
|
90
|
+
def to_year_hash
|
91
|
+
r = Hash.new {|h, k| h[k] = []}
|
92
|
+
@archive.each do |year, m|
|
93
|
+
m.each do |month, d|
|
94
|
+
d.each do |date, p|
|
95
|
+
r[year] << p
|
96
|
+
r[year].flatten!
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
r
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Writes the archive pages
|
105
|
+
def write
|
106
|
+
self.write_years if @site.layouts['archive_year']
|
107
|
+
self.write_months if @site.layouts['archive_month']
|
108
|
+
self.write_dates if @site.layouts['archive_date']
|
109
|
+
end
|
110
|
+
|
111
|
+
def write_years
|
112
|
+
years = self.to_year_hash
|
113
|
+
years.each do |year, posts|
|
114
|
+
write_path = File.join( @config[:root], year, 'index.html' )
|
115
|
+
# date should give the full date, as a Time object!! and the others
|
116
|
+
t = Time.parse("#{year}/01/01")
|
117
|
+
payload = {:name => 'archive', :payload => {'date' => t, 'posts' => years[year]} }
|
118
|
+
page = Gen.new( write_path, @site, payload )
|
119
|
+
page.layout = @site.layouts['archive_year']
|
120
|
+
|
121
|
+
page.render
|
122
|
+
page.write
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def write_months
|
127
|
+
months = self.to_month_hash
|
128
|
+
months.each do |year, posts|
|
129
|
+
posts.each do |month, posts|
|
130
|
+
write_path = File.join( @config[:root], year, month, 'index.html' )
|
131
|
+
t = Time.parse("#{year}/#{month}/01")
|
132
|
+
payload = {:name => 'archive', :payload => {'date' => t, 'posts' => months[year][month]} }
|
133
|
+
page = Gen.new( write_path, @site, payload )
|
134
|
+
page.layout = @site.layouts['archive_month']
|
135
|
+
|
136
|
+
page.render
|
137
|
+
page.write
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def write_dates
|
143
|
+
dates = self.to_date_hash
|
144
|
+
dates.each do |year, posts|
|
145
|
+
posts.each do |month, posts|
|
146
|
+
posts.each do |date, posts|
|
147
|
+
write_path = File.join( @config[:root], year, month, date, 'index.html' )
|
148
|
+
t = Time.parse("#{year}/#{month}/#{date}")
|
149
|
+
payload = {:name => 'archive', :payload => {'date' => t, 'posts' => dates[year][month][date]} }
|
150
|
+
page = Gen.new( write_path, @site, payload )
|
151
|
+
page.layout = @site.layouts['archive_date']
|
152
|
+
|
153
|
+
page.render
|
154
|
+
page.write
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
data/lib/henshin/categories.rb
CHANGED
@@ -11,10 +11,15 @@ module Henshin
|
|
11
11
|
def to_hash
|
12
12
|
hash = {
|
13
13
|
'name' => @name,
|
14
|
-
'posts' => @posts.collect {|i| i.to_hash}
|
14
|
+
'posts' => @posts.sort.collect {|i| i.to_hash},
|
15
|
+
'url' => self.url
|
15
16
|
}
|
16
17
|
end
|
17
18
|
|
19
|
+
def url
|
20
|
+
"/categories/#{@name.slugify}/"
|
21
|
+
end
|
22
|
+
|
18
23
|
|
19
24
|
def inspect
|
20
25
|
"#<Category:#{@name}>"
|
data/lib/henshin/ext.rb
CHANGED
@@ -25,7 +25,7 @@ def Exception.ignoring_exceptions
|
|
25
25
|
begin
|
26
26
|
yield
|
27
27
|
rescue Exception => e
|
28
|
-
STDERR.puts e
|
28
|
+
STDERR.puts e
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -58,19 +58,10 @@ class String
|
|
58
58
|
slug
|
59
59
|
end
|
60
60
|
|
61
|
-
# Capitalizes the string using Gruber's guidelines
|
62
|
-
def titlize
|
63
|
-
self
|
64
|
-
end
|
65
|
-
|
66
61
|
# Gets the extension from a string
|
67
62
|
def extension
|
68
63
|
parts = self.split('.')
|
69
|
-
|
70
|
-
return parts[1]
|
71
|
-
elsif parts.size == 3
|
72
|
-
return parts[2]
|
73
|
-
end
|
64
|
+
parts[parts.size-1]
|
74
65
|
end
|
75
66
|
|
76
67
|
# Gets the directory from a string
|
@@ -84,46 +75,4 @@ class String
|
|
84
75
|
self.dup.gsub(/([a-zA-Z0-9_-]+\/)/, '')
|
85
76
|
end
|
86
77
|
|
87
|
-
|
88
|
-
|
89
|
-
# Methods to determine whether the file at the path is a post, layout, gen or static
|
90
|
-
|
91
|
-
# @param [Hash] config
|
92
|
-
# @return [Bool]
|
93
|
-
# @todo see #ignored?
|
94
|
-
def static?( config )
|
95
|
-
!( self.layout? || self.post? || self.gen?(config) || self.ignored?(config) )
|
96
|
-
end
|
97
|
-
|
98
|
-
# @return [Bool]
|
99
|
-
def layout?
|
100
|
-
self.include? 'layouts/'
|
101
|
-
end
|
102
|
-
|
103
|
-
# @return [Bool]
|
104
|
-
def post?
|
105
|
-
self.include? 'posts/'
|
106
|
-
end
|
107
|
-
|
108
|
-
# @param [Hash] config
|
109
|
-
# @return [Bool]
|
110
|
-
# @todo see #ignored?
|
111
|
-
def gen?( config )
|
112
|
-
return true if config[:plugins][:generators].has_key? self.extension
|
113
|
-
return true if File.open(self, "r").read(3) == "---"
|
114
|
-
false
|
115
|
-
end
|
116
|
-
|
117
|
-
# @param [Hash] config
|
118
|
-
# @return [Bool]
|
119
|
-
# @todo Find a way around having to pass the config in
|
120
|
-
def ignored?( config )
|
121
|
-
ignored = ['/options.yaml'] + config[:exclude]
|
122
|
-
ignored.collect! {|i| File.join(config[:root], i)}
|
123
|
-
ignored.each do |i|
|
124
|
-
return true if self.include? i
|
125
|
-
end
|
126
|
-
false
|
127
|
-
end
|
128
|
-
|
129
78
|
end
|
data/lib/henshin/gen.rb
CHANGED
@@ -3,7 +3,7 @@ module Henshin
|
|
3
3
|
# This is the main class for all pages, posts, sass, etc, that need to be run through a plugin
|
4
4
|
class Gen
|
5
5
|
|
6
|
-
attr_accessor :path, :extension, :content, :layout, :
|
6
|
+
attr_accessor :path, :extension, :content, :layout, :title
|
7
7
|
attr_accessor :site, :config, :renderer, :data, :output
|
8
8
|
|
9
9
|
def initialize( path, site, data=nil )
|
@@ -40,7 +40,6 @@ module Henshin
|
|
40
40
|
def override( override )
|
41
41
|
@title = override[:title] if override[:title]
|
42
42
|
@layout = @site.layouts[ override[:layout] ] if override[:layout]
|
43
|
-
@date = Time.parse( override[:date].to_s ) if override[:date]
|
44
43
|
end
|
45
44
|
|
46
45
|
|
@@ -48,18 +47,26 @@ module Henshin
|
|
48
47
|
# Renders the files content
|
49
48
|
def render
|
50
49
|
ignore_layout = false
|
50
|
+
plugins = []
|
51
|
+
|
52
|
+
config[:plugins][:generators].each do |k, v|
|
53
|
+
if k == @extension || k == '*'
|
54
|
+
plugins << v
|
55
|
+
end
|
56
|
+
end
|
57
|
+
plugins.sort!
|
51
58
|
|
52
|
-
|
53
|
-
|
54
|
-
@
|
55
|
-
@output = plugin.extensions[:output]
|
59
|
+
plugins.each do |plugin|
|
60
|
+
@content = plugin.generate(@content)
|
61
|
+
@output = plugin.extensions[:output] if plugin.extensions[:output]
|
56
62
|
ignore_layout = true if plugin.config[:ignore_layouts]
|
57
63
|
end
|
58
|
-
|
64
|
+
|
59
65
|
@layout ||= site.layouts[ site.config[:layout] ]
|
60
66
|
unless ignore_layout || @layout.nil?
|
61
67
|
config[:plugins][:layout_parsers].each do |plugin|
|
62
68
|
@content = plugin.generate( @layout, self.payload )
|
69
|
+
@content = plugin.generate( @content, self.payload )
|
63
70
|
end
|
64
71
|
end
|
65
72
|
|
@@ -87,7 +94,6 @@ module Henshin
|
|
87
94
|
'title' => @title,
|
88
95
|
'permalink' => self.permalink,
|
89
96
|
'url' => self.url,
|
90
|
-
'date' => @date,
|
91
97
|
'content' => @content
|
92
98
|
}
|
93
99
|
end
|
@@ -122,13 +128,8 @@ module Henshin
|
|
122
128
|
|
123
129
|
|
124
130
|
# Needed to sort the posts by date, newest first
|
125
|
-
def <=>(
|
126
|
-
|
127
|
-
if s == 0
|
128
|
-
return self.permalink <=> val.permalink
|
129
|
-
else
|
130
|
-
return -1 * s
|
131
|
-
end
|
131
|
+
def <=>( other )
|
132
|
+
self.permalink <=> other.permalink
|
132
133
|
end
|
133
134
|
|
134
135
|
def inspect
|
data/lib/henshin/plugin.rb
CHANGED
@@ -8,20 +8,33 @@ module Henshin
|
|
8
8
|
|
9
9
|
attr_accessor :extensions, :config
|
10
10
|
|
11
|
+
# Defaults = {}
|
12
|
+
|
11
13
|
def initialize
|
12
14
|
# inputs are the file types it will take
|
13
15
|
# output should be the type it creates
|
14
16
|
@extensions = {:input => [],
|
15
17
|
:output => ''}
|
16
|
-
@config = {}
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
def configure( override )
|
21
|
+
if Defaults
|
22
|
+
if override
|
23
|
+
@config = Defaults.merge(override)
|
24
|
+
else
|
25
|
+
@config = Defaults
|
26
|
+
end
|
27
|
+
elsif override
|
28
|
+
@config = override
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def <=>(other)
|
33
|
+
self.priority <=> other.priority
|
34
|
+
end
|
22
35
|
|
23
36
|
# Uncomment to have the plugin loaded
|
24
|
-
# Henshin.register! self
|
37
|
+
# Henshin.register! self, :standard_plugin
|
25
38
|
end
|
26
39
|
|
27
40
|
class Generator < StandardPlugin
|
@@ -32,7 +45,7 @@ module Henshin
|
|
32
45
|
end
|
33
46
|
|
34
47
|
# Uncomment to have the plugin loaded
|
35
|
-
# Henshin.register! self
|
48
|
+
# Henshin.register! self, :generator
|
36
49
|
end
|
37
50
|
|
38
51
|
class LayoutParser < StandardPlugin
|
@@ -44,7 +57,7 @@ module Henshin
|
|
44
57
|
end
|
45
58
|
|
46
59
|
# Uncomment to have the plugin loaded
|
47
|
-
# Henshin.register! self
|
60
|
+
# Henshin.register! self, :generator
|
48
61
|
end
|
49
62
|
|
50
63
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'henshin/plugin'
|
2
|
+
require 'simplabs/highlight'
|
3
|
+
|
4
|
+
class HighlightPlugin < Henshin::Generator
|
5
|
+
|
6
|
+
attr_accessor :priority, :config, :extensions
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@extensions = {:input => ['*']}
|
10
|
+
@config = {}
|
11
|
+
@priority = 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure( override )
|
15
|
+
@config.merge!(override) if override
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate( content )
|
19
|
+
content =~ /(\$highlight)\s+(.+)((\n.*)+)(\$end)/
|
20
|
+
if $1
|
21
|
+
lang = $2.to_sym
|
22
|
+
code = $3[1..-1] # removes first new line
|
23
|
+
insert = '<pre><code>' + Simplabs::Highlight.highlight(lang, code) + '</code></pre>'
|
24
|
+
content.gsub(/(\$highlight.*\$end)/m, insert)
|
25
|
+
else
|
26
|
+
content
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Henshin.register! self
|
31
|
+
end
|
@@ -3,27 +3,61 @@ require 'liquid'
|
|
3
3
|
|
4
4
|
class LiquidPlugin < Henshin::LayoutParser
|
5
5
|
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :config
|
7
7
|
|
8
8
|
def initialize
|
9
|
-
@
|
10
|
-
|
9
|
+
@config = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def configure( override )
|
13
|
+
@config.merge!(override) if override
|
11
14
|
end
|
12
15
|
|
13
16
|
def generate( layout, data )
|
14
|
-
|
15
|
-
|
17
|
+
reg = {:include_dir => @config['include_dir']}
|
18
|
+
Liquid::Template.parse(layout).render(data, :registers => reg)
|
19
|
+
end
|
20
|
+
|
21
|
+
module Filters
|
22
|
+
def date_to_string(dt)
|
23
|
+
dt.strftime "%d %b %Y"
|
24
|
+
end
|
25
|
+
|
26
|
+
def date_to_long(dt)
|
27
|
+
dt.strftime "%d %B %Y at %H:%M"
|
28
|
+
end
|
29
|
+
|
30
|
+
def time_to_string(dt)
|
31
|
+
dt.strtime "%H:%M"
|
32
|
+
end
|
33
|
+
|
34
|
+
def titlecase(str)
|
35
|
+
str.upcase
|
36
|
+
end
|
37
|
+
|
38
|
+
def escape(str)
|
39
|
+
CGI::escape str
|
40
|
+
end
|
41
|
+
|
42
|
+
def escape_html(str)
|
43
|
+
CGI::escapeHTML str
|
44
|
+
end
|
16
45
|
end
|
46
|
+
Liquid::Template.register_filter(Filters)
|
17
47
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
48
|
+
class Include < Liquid::Tag
|
49
|
+
def initialize(tag_name, file, tokens)
|
50
|
+
super
|
51
|
+
@file = file.strip
|
52
|
+
end
|
53
|
+
|
54
|
+
def render(context)
|
55
|
+
include = File.join(context.registers[:include_dir], @file)
|
56
|
+
File.open(include, 'r') {|f| f.read}
|
57
|
+
end
|
26
58
|
end
|
59
|
+
Liquid::Template.register_tag('include', Include)
|
27
60
|
|
28
|
-
Henshin.register! self
|
61
|
+
Henshin.register! self, :liquid
|
29
62
|
end
|
63
|
+
|