ruhoh 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/Gemfile +13 -0
  2. data/README.md +5 -53
  3. data/Rakefile +56 -0
  4. data/bin/ruhoh +23 -14
  5. data/lib/ruhoh/client/client.rb +310 -0
  6. data/lib/ruhoh/client/help.yml +56 -0
  7. data/lib/ruhoh/compiler.rb +16 -19
  8. data/lib/ruhoh/converters/converter.rb +30 -3
  9. data/lib/ruhoh/db.rb +7 -17
  10. data/lib/ruhoh/deployers/s3.rb +71 -0
  11. data/lib/ruhoh/friend.rb +71 -0
  12. data/lib/ruhoh/page.rb +41 -11
  13. data/lib/ruhoh/parsers/drafts.rb +54 -0
  14. data/lib/ruhoh/parsers/layouts.rb +14 -9
  15. data/lib/ruhoh/parsers/pages.rb +47 -35
  16. data/lib/ruhoh/parsers/partials.rb +14 -2
  17. data/lib/ruhoh/parsers/posts.rb +139 -88
  18. data/lib/ruhoh/parsers/routes.rb +4 -8
  19. data/lib/ruhoh/parsers/site.rb +2 -8
  20. data/lib/ruhoh/previewer.rb +48 -0
  21. data/lib/ruhoh/templaters/base.rb +53 -0
  22. data/lib/ruhoh/templaters/helpers.rb +159 -0
  23. data/lib/ruhoh/templaters/rmustache.rb +29 -0
  24. data/lib/ruhoh/utils.rb +25 -7
  25. data/lib/ruhoh/version.rb +1 -1
  26. data/lib/ruhoh/watch.rb +22 -9
  27. data/lib/ruhoh.rb +74 -29
  28. data/ruhoh.gemspec +70 -9
  29. data/scaffolds/blog/_config.yml +33 -0
  30. data/scaffolds/blog/_drafts/.gitkeep +0 -0
  31. data/scaffolds/blog/_posts/.gitkeep +0 -0
  32. data/scaffolds/blog/_site.yml +16 -0
  33. data/scaffolds/blog/_templates/partials/categories_list +3 -0
  34. data/scaffolds/blog/_templates/partials/pages_list +7 -0
  35. data/scaffolds/blog/_templates/partials/posts_collate +9 -0
  36. data/scaffolds/blog/_templates/partials/posts_list +1 -0
  37. data/scaffolds/blog/_templates/partials/tags_list +3 -0
  38. data/scaffolds/blog/_templates/syntax/google_prettify/default.css +52 -0
  39. data/scaffolds/blog/_templates/syntax/google_prettify/desert.css +34 -0
  40. data/scaffolds/blog/_templates/syntax/google_prettify/sons-of-obsidian.css +117 -0
  41. data/scaffolds/blog/_templates/syntax/google_prettify/sunburst.css +51 -0
  42. data/scaffolds/blog/_templates/syntax/google_prettify/twitter-bootstrap.css +30 -0
  43. data/scaffolds/blog/_templates/themes/twitter/bootstrap/css/bootstrap.min.css +689 -0
  44. data/scaffolds/blog/_templates/themes/twitter/bootstrap/img/glyphicons-halflings-white.png +0 -0
  45. data/scaffolds/blog/_templates/themes/twitter/bootstrap/img/glyphicons-halflings.png +0 -0
  46. data/scaffolds/blog/_templates/themes/twitter/css/style.css +68 -0
  47. data/scaffolds/blog/_templates/themes/twitter/layouts/default.html +64 -0
  48. data/scaffolds/blog/_templates/themes/twitter/layouts/page.html +13 -0
  49. data/scaffolds/blog/_templates/themes/twitter/layouts/post.html +55 -0
  50. data/scaffolds/blog/_templates/themes/twitter/manifest.yml +11 -0
  51. data/scaffolds/blog/about.md +5 -0
  52. data/scaffolds/blog/archive.html +11 -0
  53. data/scaffolds/blog/categories.html +21 -0
  54. data/scaffolds/blog/config.ru +9 -0
  55. data/scaffolds/blog/index.html +13 -0
  56. data/scaffolds/blog/pages.html +14 -0
  57. data/scaffolds/blog/tags.html +21 -0
  58. data/scaffolds/layout.html +3 -0
  59. data/scaffolds/page.html +6 -0
  60. data/scaffolds/post.html +8 -0
  61. data/scaffolds/theme/css/style.css +0 -0
  62. data/scaffolds/theme/images/.gitkeep +0 -0
  63. data/scaffolds/theme/layouts/default.html +17 -0
  64. data/scaffolds/theme/layouts/page.html +7 -0
  65. data/scaffolds/theme/layouts/post.html +8 -0
  66. data/scaffolds/theme/partials/.gitkeep +0 -0
  67. data/spec/db_spec.rb +88 -0
  68. data/spec/page_spec.rb +200 -0
  69. data/spec/parsers/layouts_spec.rb +32 -0
  70. data/spec/parsers/pages_spec.rb +97 -0
  71. data/spec/parsers/posts_spec.rb +301 -0
  72. data/spec/parsers/routes_spec.rb +45 -0
  73. data/spec/parsers/site_spec.rb +32 -0
  74. data/spec/setup_spec.rb +72 -0
  75. data/spec/spec_helper.rb +23 -0
  76. data/system_partials/analytics/getclicky +12 -0
  77. data/system_partials/analytics/google +11 -0
  78. data/system_partials/comments/disqus +13 -0
  79. data/system_partials/comments/facebook +9 -0
  80. data/system_partials/comments/intensedebate +6 -0
  81. data/system_partials/comments/livefyre +6 -0
  82. data/system_partials/syntax/google_prettify +11 -0
  83. metadata +84 -23
  84. data/lib/ruhoh/client.rb +0 -28
  85. data/lib/ruhoh/preview.rb +0 -36
  86. data/lib/ruhoh/templaters/helper_mustache.rb +0 -109
  87. data/lib/ruhoh/templaters/templater.rb +0 -39
@@ -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
- puts "=> Generating Posts..."
11
+
12
+ dictionary = self.process
13
+ ordered_posts = self.ordered_posts(dictionary)
14
14
 
15
- dictionary, invalid_posts = process_posts
16
- ordered_posts = []
17
- dictionary.each_value { |val| ordered_posts << val }
18
-
19
- ordered_posts.sort! {
20
- |a,b| Date.parse(b['date']) <=> Date.parse(a['date'])
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
- data = {
24
- 'dictionary' => dictionary,
25
- 'chronological' => build_chronology(ordered_posts),
26
- 'collated' => collate(ordered_posts),
27
- 'tags' => parse_tags(ordered_posts),
28
- 'categories' => parse_categories(ordered_posts)
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
- if invalid_posts.empty?
32
- puts "=> #{dictionary.count}/#{dictionary.count + invalid_posts.count} posts processed."
33
- else
34
- puts "=> Invalid posts not processed:"
35
- puts invalid_posts.to_yaml
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
- data
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
- def self.process_posts
42
- dictionary = {}
43
- invalid_posts = []
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.glob("#{Ruhoh.folders.posts}/**/*.*") { |filename|
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
- [dictionary, invalid_posts]
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 = case (post['permalink'] || Ruhoh.config.permalink)
92
- when :pretty
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'] || post['category']).join('/'),
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(posts)
122
- posts.map { |post| post['id'] }
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(posts)
179
+ def self.collate(ordered_posts)
135
180
  collated = []
136
- posts.each_with_index do |post, i|
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 posts[i-1]
140
- prevYear = Time.parse(posts[i-1]['date']).strftime('%Y')
141
- prevMonth = Time.parse(posts[i-1]['date']).strftime('%B')
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(posts)
213
+ def self.parse_tags(ordered_posts)
169
214
  tags = {}
170
215
 
171
- posts.each do |post|
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] = { 'count' => 1, 'name' => tag, 'posts' => [] }
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(posts)
235
+ def self.parse_categories(ordered_posts)
186
236
  categories = {}
187
237
 
188
- posts.each do |post|
189
- cats = post['categories'] ? post['categories'] : Array(post['category']).join('/')
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] = { 'count' => 1, 'name' => cat, 'posts' => [] }
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
@@ -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::Parsers::Pages.generate.each_value { |page|
7
+ Ruhoh::DB.pages.each_value { |page|
11
8
  routes[page['url']] = page['id']
12
9
  }
13
- Ruhoh::Parsers::Posts.generate['dictionary'].each_value { |page|
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
@@ -6,14 +6,8 @@ class Ruhoh
6
6
  module Site
7
7
 
8
8
  def self.generate
9
- site = File.join(Ruhoh.paths.site_source, Ruhoh.files.site)
10
- site = File.exist?(site) ? File.open(site).read : ''
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('{', '&#123;').gsub('}', '&#125;').gsub('<', '&lt;').gsub('>', '&gt;')
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