henshin 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|