ruhoh 0.0.2 → 0.0.3
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/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
|