ruhoh 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +13 -0
- data/README.md +5 -53
- data/Rakefile +56 -0
- data/bin/ruhoh +23 -14
- data/lib/ruhoh/client/client.rb +310 -0
- data/lib/ruhoh/client/help.yml +56 -0
- data/lib/ruhoh/compiler.rb +16 -19
- data/lib/ruhoh/converters/converter.rb +30 -3
- data/lib/ruhoh/db.rb +7 -17
- data/lib/ruhoh/deployers/s3.rb +71 -0
- data/lib/ruhoh/friend.rb +71 -0
- data/lib/ruhoh/page.rb +41 -11
- data/lib/ruhoh/parsers/drafts.rb +54 -0
- data/lib/ruhoh/parsers/layouts.rb +14 -9
- data/lib/ruhoh/parsers/pages.rb +47 -35
- data/lib/ruhoh/parsers/partials.rb +14 -2
- data/lib/ruhoh/parsers/posts.rb +139 -88
- data/lib/ruhoh/parsers/routes.rb +4 -8
- data/lib/ruhoh/parsers/site.rb +2 -8
- data/lib/ruhoh/previewer.rb +48 -0
- data/lib/ruhoh/templaters/base.rb +53 -0
- data/lib/ruhoh/templaters/helpers.rb +159 -0
- data/lib/ruhoh/templaters/rmustache.rb +29 -0
- data/lib/ruhoh/utils.rb +25 -7
- data/lib/ruhoh/version.rb +1 -1
- data/lib/ruhoh/watch.rb +22 -9
- data/lib/ruhoh.rb +74 -29
- data/ruhoh.gemspec +70 -9
- data/scaffolds/blog/_config.yml +33 -0
- data/scaffolds/blog/_drafts/.gitkeep +0 -0
- data/scaffolds/blog/_posts/.gitkeep +0 -0
- data/scaffolds/blog/_site.yml +16 -0
- data/scaffolds/blog/_templates/partials/categories_list +3 -0
- data/scaffolds/blog/_templates/partials/pages_list +7 -0
- data/scaffolds/blog/_templates/partials/posts_collate +9 -0
- data/scaffolds/blog/_templates/partials/posts_list +1 -0
- data/scaffolds/blog/_templates/partials/tags_list +3 -0
- data/scaffolds/blog/_templates/syntax/google_prettify/default.css +52 -0
- data/scaffolds/blog/_templates/syntax/google_prettify/desert.css +34 -0
- data/scaffolds/blog/_templates/syntax/google_prettify/sons-of-obsidian.css +117 -0
- data/scaffolds/blog/_templates/syntax/google_prettify/sunburst.css +51 -0
- data/scaffolds/blog/_templates/syntax/google_prettify/twitter-bootstrap.css +30 -0
- data/scaffolds/blog/_templates/themes/twitter/bootstrap/css/bootstrap.min.css +689 -0
- data/scaffolds/blog/_templates/themes/twitter/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/scaffolds/blog/_templates/themes/twitter/bootstrap/img/glyphicons-halflings.png +0 -0
- data/scaffolds/blog/_templates/themes/twitter/css/style.css +68 -0
- data/scaffolds/blog/_templates/themes/twitter/layouts/default.html +64 -0
- data/scaffolds/blog/_templates/themes/twitter/layouts/page.html +13 -0
- data/scaffolds/blog/_templates/themes/twitter/layouts/post.html +55 -0
- data/scaffolds/blog/_templates/themes/twitter/manifest.yml +11 -0
- data/scaffolds/blog/about.md +5 -0
- data/scaffolds/blog/archive.html +11 -0
- data/scaffolds/blog/categories.html +21 -0
- data/scaffolds/blog/config.ru +9 -0
- data/scaffolds/blog/index.html +13 -0
- data/scaffolds/blog/pages.html +14 -0
- data/scaffolds/blog/tags.html +21 -0
- data/scaffolds/layout.html +3 -0
- data/scaffolds/page.html +6 -0
- data/scaffolds/post.html +8 -0
- data/scaffolds/theme/css/style.css +0 -0
- data/scaffolds/theme/images/.gitkeep +0 -0
- data/scaffolds/theme/layouts/default.html +17 -0
- data/scaffolds/theme/layouts/page.html +7 -0
- data/scaffolds/theme/layouts/post.html +8 -0
- data/scaffolds/theme/partials/.gitkeep +0 -0
- data/spec/db_spec.rb +88 -0
- data/spec/page_spec.rb +200 -0
- data/spec/parsers/layouts_spec.rb +32 -0
- data/spec/parsers/pages_spec.rb +97 -0
- data/spec/parsers/posts_spec.rb +301 -0
- data/spec/parsers/routes_spec.rb +45 -0
- data/spec/parsers/site_spec.rb +32 -0
- data/spec/setup_spec.rb +72 -0
- data/spec/spec_helper.rb +23 -0
- data/system_partials/analytics/getclicky +12 -0
- data/system_partials/analytics/google +11 -0
- data/system_partials/comments/disqus +13 -0
- data/system_partials/comments/facebook +9 -0
- data/system_partials/comments/intensedebate +6 -0
- data/system_partials/comments/livefyre +6 -0
- data/system_partials/syntax/google_prettify +11 -0
- metadata +84 -23
- data/lib/ruhoh/client.rb +0 -28
- data/lib/ruhoh/preview.rb +0 -36
- data/lib/ruhoh/templaters/helper_mustache.rb +0 -109
- data/lib/ruhoh/templaters/templater.rb +0 -39
data/lib/ruhoh/parsers/posts.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
class Ruhoh
|
2
|
-
|
3
2
|
module Parsers
|
4
|
-
|
5
3
|
module Posts
|
6
4
|
|
7
5
|
MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
|
@@ -10,95 +8,142 @@ class Ruhoh
|
|
10
8
|
#
|
11
9
|
def self.generate
|
12
10
|
raise "Ruhoh.config cannot be nil.\n To set config call: Ruhoh.setup" unless Ruhoh.config
|
13
|
-
|
11
|
+
|
12
|
+
dictionary = self.process
|
13
|
+
ordered_posts = self.ordered_posts(dictionary)
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
{
|
16
|
+
'dictionary' => dictionary,
|
17
|
+
'chronological' => self.build_chronology(ordered_posts),
|
18
|
+
'collated' => self.collate(ordered_posts),
|
19
|
+
'tags' => self.parse_tags(ordered_posts),
|
20
|
+
'categories' => self.parse_categories(ordered_posts)
|
21
21
|
}
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
def self.process
|
25
|
+
dictionary = {}
|
26
|
+
invalid = []
|
27
|
+
|
28
|
+
self.files.each do |filename|
|
29
|
+
parsed_page = Ruhoh::Utils.parse_file(filename)
|
30
|
+
if parsed_page.empty?
|
31
|
+
error = "Invalid YAML Front Matter. Ensure this page has valid YAML, even if it's empty."
|
32
|
+
invalid << [filename, error] ; next
|
33
|
+
end
|
34
|
+
data = parsed_page['data']
|
35
|
+
|
36
|
+
filename_data = self.parse_filename(filename)
|
37
|
+
if filename_data.empty?
|
38
|
+
error = "Invalid Filename Format. Format should be: YYYY-MM-DD-my-post-title.ext"
|
39
|
+
invalid << [filename, error] ; next
|
40
|
+
end
|
41
|
+
|
42
|
+
data['date'] ||= filename_data['date']
|
30
43
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
44
|
+
unless self.formatted_date(data['date'])
|
45
|
+
error = "Invalid Date Format. Date should be: YYYY-MM-DD"
|
46
|
+
invalid << [filename, error] ; next
|
47
|
+
end
|
48
|
+
|
49
|
+
data['date'] = data['date'].to_s
|
50
|
+
data['id'] = filename
|
51
|
+
data['title'] = data['title'] || filename_data['title']
|
52
|
+
data['url'] = self.permalink(data)
|
53
|
+
dictionary[filename] = data
|
36
54
|
end
|
37
|
-
|
38
|
-
|
55
|
+
|
56
|
+
self.report(dictionary, invalid)
|
57
|
+
dictionary
|
39
58
|
end
|
59
|
+
|
60
|
+
|
61
|
+
def self.process_file(filename)
|
62
|
+
p = Ruhoh::Utils.parse_file(filename)
|
63
|
+
filename_data = self.parse_filename(filename)
|
64
|
+
|
65
|
+
if p['data']['title'].nil? || p['data']['title'].gsub(/\s/, '').empty?
|
66
|
+
p['data']['title'] = filename_data['title'] || nil
|
67
|
+
end
|
40
68
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
69
|
+
p['data']['date'] ||= filename_data['date']
|
70
|
+
p['data']['date'] = self.formatted_date(p['data']['date'] || Time.now)
|
71
|
+
|
72
|
+
p
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.formatted_date(date)
|
76
|
+
Time.parse(date.to_s).strftime('%Y-%m-%d')
|
77
|
+
rescue
|
78
|
+
false
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.report(dictionary, invalid)
|
82
|
+
output = "#{dictionary.count}/#{dictionary.count + invalid.count} posts processed."
|
83
|
+
if dictionary.empty? && invalid.empty?
|
84
|
+
Ruhoh::Friend.say { plain "0 posts to process." }
|
85
|
+
elsif invalid.empty?
|
86
|
+
Ruhoh::Friend.say { green output }
|
87
|
+
else
|
88
|
+
Ruhoh::Friend.say {
|
89
|
+
yellow output
|
90
|
+
list "Posts not processed:", invalid
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.files
|
45
96
|
FileUtils.cd(Ruhoh.paths.site_source) {
|
46
|
-
Dir
|
97
|
+
return Dir["#{Ruhoh.folders.posts}/**/*.*"].select { |filename|
|
47
98
|
next if FileTest.directory?(filename)
|
48
99
|
next if ['.'].include? filename[0]
|
49
|
-
|
50
|
-
File.open(filename) do |page|
|
51
|
-
front_matter = page.read.match(Ruhoh::Utils::FMregex)
|
52
|
-
if !front_matter
|
53
|
-
invalid_posts << filename ; next
|
54
|
-
end
|
55
|
-
|
56
|
-
post = YAML.load(front_matter[0].gsub(/---\n/, "")) || {}
|
57
|
-
|
58
|
-
m, path, file_date, file_slug, ext = *filename.match(MATCHER)
|
59
|
-
post['date'] = post['date'] || file_date
|
60
|
-
|
61
|
-
## Test for valid date
|
62
|
-
begin
|
63
|
-
Time.parse(post['date'])
|
64
|
-
rescue
|
65
|
-
puts "Invalid date format on: #{filename}"
|
66
|
-
puts "Date should be: YYYY/MM/DD"
|
67
|
-
invalid_posts << filename
|
68
|
-
next
|
69
|
-
end
|
70
|
-
|
71
|
-
post['id'] = filename
|
72
|
-
post['title'] = post['title'] || self.titleize(file_slug)
|
73
|
-
post['url'] = self.permalink(post)
|
74
|
-
dictionary[filename] = post
|
75
|
-
end
|
100
|
+
true
|
76
101
|
}
|
77
102
|
}
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.ordered_posts(dictionary)
|
106
|
+
ordered_posts = []
|
107
|
+
dictionary.each_value { |val| ordered_posts << val }
|
108
|
+
ordered_posts.sort! {
|
109
|
+
|a,b| Date.parse(b['date']) <=> Date.parse(a['date'])
|
110
|
+
}
|
78
111
|
|
79
|
-
|
112
|
+
ordered_posts
|
80
113
|
end
|
81
|
-
|
114
|
+
|
115
|
+
def self.parse_filename(filename)
|
116
|
+
data = *filename.match(MATCHER)
|
117
|
+
return {} if data.empty?
|
118
|
+
{
|
119
|
+
"path" => data[1],
|
120
|
+
"date" => data[2],
|
121
|
+
"slug" => data[3],
|
122
|
+
"title" => self.titleize(data[3]),
|
123
|
+
"extension" => data[4]
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
82
127
|
# my-post-title ===> My Post Title
|
83
128
|
def self.titleize(file_slug)
|
84
129
|
file_slug.gsub(/[\W\_]/, ' ').gsub(/\b\w/){$&.upcase}
|
85
130
|
end
|
86
131
|
|
132
|
+
# My Post Title ===> my-post-title
|
133
|
+
def self.to_slug(title)
|
134
|
+
title.downcase.strip.gsub(/\s/, '-').gsub(/[^\w-]/, '')
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.to_filename(data)
|
138
|
+
File.join(Ruhoh.paths.posts, "#{self.formatted_date(data['date'])}-#{self.to_slug(data['title'])}.#{data['ext']}")
|
139
|
+
end
|
140
|
+
|
87
141
|
# Another blatently stolen method from Jekyll
|
88
142
|
def self.permalink(post)
|
89
143
|
date = Date.parse(post['date'])
|
90
144
|
title = post['title'].downcase.gsub(' ', '-').gsub('.','')
|
91
|
-
format =
|
92
|
-
|
93
|
-
"/:categories/:year/:month/:day/:title/"
|
94
|
-
when :none
|
95
|
-
"/:categories/:title.html"
|
96
|
-
when :date
|
97
|
-
"/:categories/:year/:month/:day/:title.html"
|
98
|
-
else
|
99
|
-
post['permalink'] || Ruhoh.config.permalink
|
100
|
-
end
|
101
|
-
|
145
|
+
format = post['permalink'] || Ruhoh.config.permalink || "/:categories/:year/:month/:day/:title.html"
|
146
|
+
|
102
147
|
url = {
|
103
148
|
"year" => date.strftime("%Y"),
|
104
149
|
"month" => date.strftime("%m"),
|
@@ -106,7 +151,7 @@ class Ruhoh
|
|
106
151
|
"title" => CGI::escape(title),
|
107
152
|
"i_day" => date.strftime("%d").to_i.to_s,
|
108
153
|
"i_month" => date.strftime("%m").to_i.to_s,
|
109
|
-
"categories" => Array(post['categories'] ||
|
154
|
+
"categories" => Array(post['categories'])[0] || '',
|
110
155
|
"output_ext" => 'html' # what's this for?
|
111
156
|
}.inject(format) { |result, token|
|
112
157
|
result.gsub(/:#{Regexp.escape token.first}/, token.last)
|
@@ -118,8 +163,8 @@ class Ruhoh
|
|
118
163
|
url
|
119
164
|
end
|
120
165
|
|
121
|
-
def self.build_chronology(
|
122
|
-
|
166
|
+
def self.build_chronology(ordered_posts)
|
167
|
+
ordered_posts.map { |post| post['id'] }
|
123
168
|
end
|
124
169
|
|
125
170
|
# Internal: Create a collated posts data structure.
|
@@ -131,16 +176,16 @@ class Ruhoh
|
|
131
176
|
# 'months' : [{ 'month' : month,
|
132
177
|
# 'posts': [{}, {}, ..] }, ..] }, ..]
|
133
178
|
#
|
134
|
-
def self.collate(
|
179
|
+
def self.collate(ordered_posts)
|
135
180
|
collated = []
|
136
|
-
|
181
|
+
ordered_posts.each_with_index do |post, i|
|
137
182
|
thisYear = Time.parse(post['date']).strftime('%Y')
|
138
183
|
thisMonth = Time.parse(post['date']).strftime('%B')
|
139
|
-
if
|
140
|
-
prevYear = Time.parse(
|
141
|
-
prevMonth = Time.parse(
|
184
|
+
if (i-1 >= 0)
|
185
|
+
prevYear = Time.parse(ordered_posts[i-1]['date']).strftime('%Y')
|
186
|
+
prevMonth = Time.parse(ordered_posts[i-1]['date']).strftime('%B')
|
142
187
|
end
|
143
|
-
|
188
|
+
|
144
189
|
if(prevYear == thisYear)
|
145
190
|
if(prevMonth == thisMonth)
|
146
191
|
collated.last['months'].last['posts'] << post['id'] # append to last year & month
|
@@ -165,15 +210,20 @@ class Ruhoh
|
|
165
210
|
collated
|
166
211
|
end
|
167
212
|
|
168
|
-
def self.parse_tags(
|
213
|
+
def self.parse_tags(ordered_posts)
|
169
214
|
tags = {}
|
170
215
|
|
171
|
-
|
216
|
+
ordered_posts.each do |post|
|
172
217
|
Array(post['tags']).each do |tag|
|
173
218
|
if tags[tag]
|
174
219
|
tags[tag]['count'] += 1
|
175
220
|
else
|
176
|
-
tags[tag] = {
|
221
|
+
tags[tag] = {
|
222
|
+
'count' => 1,
|
223
|
+
'name' => tag,
|
224
|
+
'url' => "/tags.html##{tag}-ref",
|
225
|
+
'posts' => []
|
226
|
+
}
|
177
227
|
end
|
178
228
|
|
179
229
|
tags[tag]['posts'] << post['id']
|
@@ -182,18 +232,21 @@ class Ruhoh
|
|
182
232
|
tags
|
183
233
|
end
|
184
234
|
|
185
|
-
def self.parse_categories(
|
235
|
+
def self.parse_categories(ordered_posts)
|
186
236
|
categories = {}
|
187
237
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
Array(cats).each do |cat|
|
238
|
+
ordered_posts.each do |post|
|
239
|
+
Array(post['categories']).each do |cat|
|
192
240
|
cat = Array(cat).join('/')
|
193
241
|
if categories[cat]
|
194
242
|
categories[cat]['count'] += 1
|
195
243
|
else
|
196
|
-
categories[cat] = {
|
244
|
+
categories[cat] = {
|
245
|
+
'count' => 1,
|
246
|
+
'name' => cat,
|
247
|
+
'url' => "/categories.html##{cat}-ref",
|
248
|
+
'posts' => []
|
249
|
+
}
|
197
250
|
end
|
198
251
|
|
199
252
|
categories[cat]['posts'] << post['id']
|
@@ -203,7 +256,5 @@ class Ruhoh
|
|
203
256
|
end
|
204
257
|
|
205
258
|
end # Post
|
206
|
-
|
207
259
|
end #Parsers
|
208
|
-
|
209
260
|
end #Ruhoh
|
data/lib/ruhoh/parsers/routes.rb
CHANGED
@@ -1,24 +1,20 @@
|
|
1
1
|
class Ruhoh
|
2
|
-
|
3
2
|
module Parsers
|
4
|
-
|
5
3
|
module Routes
|
6
4
|
|
7
|
-
#[{"url" => "id"}, ... ]
|
8
5
|
def self.generate
|
9
6
|
routes = {}
|
10
|
-
Ruhoh::
|
7
|
+
Ruhoh::DB.pages.each_value { |page|
|
11
8
|
routes[page['url']] = page['id']
|
12
9
|
}
|
13
|
-
|
10
|
+
|
11
|
+
Ruhoh::DB.posts['dictionary'].each_value { |page|
|
14
12
|
routes[page['url']] = page['id']
|
15
13
|
}
|
16
|
-
|
14
|
+
|
17
15
|
routes
|
18
16
|
end
|
19
17
|
|
20
18
|
end #Routes
|
21
|
-
|
22
19
|
end #Parsers
|
23
|
-
|
24
20
|
end #Ruhoh
|
data/lib/ruhoh/parsers/site.rb
CHANGED
@@ -6,14 +6,8 @@ class Ruhoh
|
|
6
6
|
module Site
|
7
7
|
|
8
8
|
def self.generate
|
9
|
-
site =
|
10
|
-
|
11
|
-
site = YAML.load(site) || {}
|
12
|
-
|
13
|
-
config = File.join(Ruhoh.paths.site_source, Ruhoh.files.config)
|
14
|
-
config = File.exist?(config) ? File.open(config).read : ''
|
15
|
-
config = YAML.load(config) || {}
|
16
|
-
|
9
|
+
site = Ruhoh::Utils.parse_file_as_yaml(Ruhoh.paths.site_source, Ruhoh.files.site) || {}
|
10
|
+
config = Ruhoh::Utils.parse_file_as_yaml(Ruhoh.paths.site_source, Ruhoh.files.config)
|
17
11
|
site['config'] = config
|
18
12
|
site
|
19
13
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Ruhoh
|
2
|
+
|
3
|
+
# Public: Rack application used to render singular pages via their URL.
|
4
|
+
#
|
5
|
+
# Examples
|
6
|
+
#
|
7
|
+
# In config.ru:
|
8
|
+
#
|
9
|
+
# require 'ruhoh'
|
10
|
+
#
|
11
|
+
# Ruhoh.setup
|
12
|
+
# use Rack::Static, {:urls => ["/#{Ruhoh.folders.media}", "/#{Ruhoh.folders.templates}"]}
|
13
|
+
# run Ruhoh::Previewer.new
|
14
|
+
#
|
15
|
+
class Previewer
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
Ruhoh::DB.update!
|
19
|
+
@page = Ruhoh::Page.new
|
20
|
+
Ruhoh::Watch.start
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(env)
|
24
|
+
return favicon if env['PATH_INFO'] == '/favicon.ico'
|
25
|
+
return drafts if ["/#{Ruhoh.folders.drafts}", "/#{Ruhoh.folders.drafts}/"].include?(env['PATH_INFO'])
|
26
|
+
|
27
|
+
@page.change_with_url(env['PATH_INFO'])
|
28
|
+
[200, {'Content-Type' => 'text/html'}, [@page.render]]
|
29
|
+
end
|
30
|
+
|
31
|
+
def favicon
|
32
|
+
[200, {'Content-Type' => 'image/x-icon'}, ['']]
|
33
|
+
end
|
34
|
+
|
35
|
+
def drafts
|
36
|
+
html = '<h3>Drafts</h3>'
|
37
|
+
html += '<ul>'
|
38
|
+
Ruhoh::DB.drafts.each_value do |draft|
|
39
|
+
html += "<li><a href='#{draft['url']}'>#{draft['id']}: #{draft['title']}</a></li>"
|
40
|
+
end
|
41
|
+
html += '</ul>'
|
42
|
+
|
43
|
+
[200, {'Content-Type' => 'text/html'}, [html]]
|
44
|
+
end
|
45
|
+
|
46
|
+
end #Previewer
|
47
|
+
|
48
|
+
end #Ruhoh
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Ruhoh
|
2
|
+
|
3
|
+
module Templaters
|
4
|
+
|
5
|
+
module Base
|
6
|
+
|
7
|
+
def self.build_payload(page)
|
8
|
+
{
|
9
|
+
"page" => page.attributes,
|
10
|
+
"site" => Ruhoh::DB.site,
|
11
|
+
"pages" => Ruhoh::DB.pages,
|
12
|
+
"_posts" => Ruhoh::DB.posts,
|
13
|
+
"THEME_PATH" => Ruhoh.config.theme_path,
|
14
|
+
"SYNTAX_PATH" => Ruhoh.config.syntax_path,
|
15
|
+
"MEDIA_PATH" => Ruhoh.config.media_path
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Render a given page object.
|
20
|
+
# This is different from parse only in that rendering a page
|
21
|
+
# assumes we use page.content and its layouts as the incoming view.
|
22
|
+
def self.render(page)
|
23
|
+
self.parse(self.expand(page), page)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Parse arbitrary content relative to a given page.
|
27
|
+
def self.parse(output, page)
|
28
|
+
Ruhoh::Templaters::RMustache.render(output, self.build_payload(page))
|
29
|
+
end
|
30
|
+
|
31
|
+
# Expand the page.
|
32
|
+
# Places page content into sub-template then into master template if available.
|
33
|
+
def self.expand(page)
|
34
|
+
if page.sub_layout
|
35
|
+
output = page.sub_layout['content'].gsub(Ruhoh::Utils::ContentRegex, page.content)
|
36
|
+
else
|
37
|
+
output = page.content
|
38
|
+
end
|
39
|
+
|
40
|
+
# An undefined master means the page/post layouts is only one deep.
|
41
|
+
# This means it expects to load directly into a master template.
|
42
|
+
if page.master_layout && page.master_layout['content']
|
43
|
+
output = page.master_layout['content'].gsub(Ruhoh::Utils::ContentRegex, output);
|
44
|
+
end
|
45
|
+
|
46
|
+
output
|
47
|
+
end
|
48
|
+
|
49
|
+
end #Base
|
50
|
+
|
51
|
+
end #Templaters
|
52
|
+
|
53
|
+
end #Ruhoh
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
class Ruhoh
|
4
|
+
|
5
|
+
module Templaters
|
6
|
+
|
7
|
+
module Helpers
|
8
|
+
|
9
|
+
def partial(name)
|
10
|
+
Ruhoh::DB.partials[name.to_s]
|
11
|
+
end
|
12
|
+
|
13
|
+
def raw_code(sub_context)
|
14
|
+
code = sub_context.gsub('{', '{').gsub('}', '}').gsub('<', '<').gsub('>', '>')
|
15
|
+
"<pre><code>#{code}</code></pre>"
|
16
|
+
end
|
17
|
+
|
18
|
+
def debug(sub_context)
|
19
|
+
Ruhoh::Friend.say {
|
20
|
+
yellow "?debug:"
|
21
|
+
magenta sub_context.class
|
22
|
+
cyan sub_context.inspect
|
23
|
+
}
|
24
|
+
|
25
|
+
"<pre>#{sub_context.class}\n#{sub_context.pretty_inspect}</pre>"
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_tags(sub_context)
|
29
|
+
if sub_context.is_a?(Array)
|
30
|
+
sub_context.map { |id|
|
31
|
+
self.context['_posts']['tags'][id] if self.context['_posts']['tags'][id]
|
32
|
+
}
|
33
|
+
else
|
34
|
+
tags = []
|
35
|
+
self.context['_posts']['tags'].each_value { |tag|
|
36
|
+
tags << tag
|
37
|
+
}
|
38
|
+
tags
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_posts(sub_context)
|
43
|
+
sub_context = sub_context.is_a?(Array) ? sub_context : self.context['_posts']['chronological']
|
44
|
+
|
45
|
+
sub_context.map { |id|
|
46
|
+
self.context['_posts']['dictionary'][id] if self.context['_posts']['dictionary'][id]
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_pages(sub_context)
|
51
|
+
pages = []
|
52
|
+
if sub_context.is_a?(Array)
|
53
|
+
sub_context.each do |id|
|
54
|
+
if self.context[:pages][id]
|
55
|
+
pages << self.context[:pages][id]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
else
|
59
|
+
self.context[:pages].each_value {|page| pages << page }
|
60
|
+
end
|
61
|
+
|
62
|
+
pages.each_with_index do |page, i|
|
63
|
+
next unless page['id'] == self.context[:page]['id']
|
64
|
+
active_page = page.dup
|
65
|
+
active_page['is_active_page'] = true
|
66
|
+
pages[i] = active_page
|
67
|
+
end
|
68
|
+
|
69
|
+
pages
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_categories(sub_context)
|
73
|
+
if sub_context.is_a?(Array)
|
74
|
+
sub_context.map { |id|
|
75
|
+
self.context['_posts']['categories'][id] if self.context['_posts']['categories'][id]
|
76
|
+
}
|
77
|
+
else
|
78
|
+
cats = []
|
79
|
+
self.context['_posts']['categories'].each_value { |cat|
|
80
|
+
cats << cat
|
81
|
+
}
|
82
|
+
cats
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def next(sub_context)
|
87
|
+
return unless sub_context.is_a?(String) || sub_context.is_a?(Hash)
|
88
|
+
id = sub_context.is_a?(Hash) ? sub_context['id'] : sub_context
|
89
|
+
return unless id
|
90
|
+
index = self.context['_posts']['chronological'].index(id)
|
91
|
+
return unless index && (index-1 >= 0)
|
92
|
+
next_id = self.context['_posts']['chronological'][index-1]
|
93
|
+
return unless next_id
|
94
|
+
self.to_posts([next_id])
|
95
|
+
end
|
96
|
+
|
97
|
+
def previous(sub_context)
|
98
|
+
return unless sub_context.is_a?(String) || sub_context.is_a?(Hash)
|
99
|
+
id = sub_context.is_a?(Hash) ? sub_context['id'] : sub_context
|
100
|
+
return unless id
|
101
|
+
index = self.context['_posts']['chronological'].index(id)
|
102
|
+
return unless index && (index+1 >= 0)
|
103
|
+
prev_id = self.context['_posts']['chronological'][index+1]
|
104
|
+
return unless prev_id
|
105
|
+
self.to_posts([prev_id])
|
106
|
+
end
|
107
|
+
|
108
|
+
def analytics
|
109
|
+
return '' if self.context['page']['analytics'].to_s == 'false'
|
110
|
+
analytics_config = self.context['site']['config']['analytics']
|
111
|
+
return '' unless analytics_config && analytics_config['provider']
|
112
|
+
|
113
|
+
if analytics_config['provider'] == "custom"
|
114
|
+
code = self.partial("custom_analytics")
|
115
|
+
else
|
116
|
+
code = self.partial("analytics/#{analytics_config['provider']}")
|
117
|
+
end
|
118
|
+
|
119
|
+
return "<h2 style='color:red'>!Analytics Provider partial for '#{analytics_config['provider']}' not found </h2>" if code.nil?
|
120
|
+
|
121
|
+
self.render(code)
|
122
|
+
end
|
123
|
+
|
124
|
+
def comments
|
125
|
+
return '' if self.context['page']['comments'].to_s == 'false'
|
126
|
+
comments_config = self.context['site']['config']['comments']
|
127
|
+
return '' unless comments_config && comments_config['provider']
|
128
|
+
|
129
|
+
if comments_config['provider'] == "custom"
|
130
|
+
code = self.partial("custom_comments")
|
131
|
+
else
|
132
|
+
code = self.partial("comments/#{comments_config['provider']}")
|
133
|
+
end
|
134
|
+
|
135
|
+
return "<h2 style='color:red'>!Comments Provider partial for '#{comments_config['provider']}' not found </h2>" if code.nil?
|
136
|
+
|
137
|
+
self.render(code)
|
138
|
+
end
|
139
|
+
|
140
|
+
def syntax
|
141
|
+
syntax_config = self.context['site']['config']['syntax']
|
142
|
+
return '' unless syntax_config && syntax_config['provider']
|
143
|
+
|
144
|
+
if syntax_config['provider'] == "custom"
|
145
|
+
code = self.partial("custom_syntax")
|
146
|
+
else
|
147
|
+
code = self.partial("syntax/#{syntax_config['provider']}")
|
148
|
+
end
|
149
|
+
|
150
|
+
return "<h2 style='color:red'>!Syntax Provider partial for '#{syntax_config['provider']}' not found </h2>" if code.nil?
|
151
|
+
|
152
|
+
self.render(code)
|
153
|
+
end
|
154
|
+
|
155
|
+
end #Helpers
|
156
|
+
|
157
|
+
end #Templaters
|
158
|
+
|
159
|
+
end #Ruhoh
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Ruhoh
|
2
|
+
|
3
|
+
module Templaters
|
4
|
+
|
5
|
+
class RMustache < Mustache
|
6
|
+
include Ruhoh::Templaters::Helpers
|
7
|
+
|
8
|
+
class RContext < Context
|
9
|
+
|
10
|
+
# Overload find method to catch helper expressions
|
11
|
+
def find(obj, key, default = nil)
|
12
|
+
return super unless key.to_s.index('?')
|
13
|
+
context, helper = key.to_s.split('?')
|
14
|
+
context = context.empty? ? obj : super(obj, context)
|
15
|
+
|
16
|
+
self.mustache_in_stack.__send__ helper, context
|
17
|
+
end
|
18
|
+
|
19
|
+
end #RContext
|
20
|
+
|
21
|
+
def context
|
22
|
+
@context ||= RContext.new(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
end #RMustache
|
26
|
+
|
27
|
+
end #Templaters
|
28
|
+
|
29
|
+
end #Ruhoh
|