ruhoh 0.3.0 → 1.0.0.alpha

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.
Files changed (71) hide show
  1. data/Gemfile +1 -0
  2. data/README.md +0 -33
  3. data/dash.html +1 -0
  4. data/history.json +29 -0
  5. data/lib/ruhoh/client/client.rb +30 -22
  6. data/lib/ruhoh/client/help.yml +6 -2
  7. data/lib/ruhoh/compiler.rb +8 -20
  8. data/lib/ruhoh/compilers/rss.rb +36 -0
  9. data/lib/ruhoh/compilers/theme.rb +41 -0
  10. data/lib/ruhoh/config.rb +49 -0
  11. data/lib/ruhoh/converters/converter.rb +17 -4
  12. data/lib/ruhoh/converters/markdown.rb +2 -2
  13. data/lib/ruhoh/db.rb +29 -2
  14. data/lib/ruhoh/deployers/s3.rb +1 -1
  15. data/lib/ruhoh/logger.rb +1 -1
  16. data/lib/ruhoh/page.rb +38 -22
  17. data/lib/ruhoh/parsers/javascripts.rb +67 -0
  18. data/lib/ruhoh/parsers/layouts.rb +6 -10
  19. data/lib/ruhoh/parsers/pages.rb +17 -24
  20. data/lib/ruhoh/parsers/partials.rb +6 -14
  21. data/lib/ruhoh/parsers/payload.rb +47 -0
  22. data/lib/ruhoh/parsers/posts.rb +27 -29
  23. data/lib/ruhoh/parsers/site.rb +2 -2
  24. data/lib/ruhoh/parsers/stylesheets.rb +75 -0
  25. data/lib/ruhoh/parsers/widgets.rb +104 -0
  26. data/lib/ruhoh/paths.rb +75 -0
  27. data/lib/ruhoh/previewer.rb +11 -5
  28. data/lib/ruhoh/program.rb +35 -4
  29. data/lib/ruhoh/templaters/asset_helpers.rb +66 -0
  30. data/lib/ruhoh/templaters/base_helpers.rb +143 -0
  31. data/lib/ruhoh/templaters/helpers.rb +1 -148
  32. data/lib/ruhoh/templaters/rmustache.rb +45 -4
  33. data/lib/ruhoh/urls.rb +46 -0
  34. data/lib/ruhoh/utils.rb +59 -17
  35. data/lib/ruhoh/version.rb +2 -2
  36. data/lib/ruhoh/watch.rb +26 -14
  37. data/lib/ruhoh.rb +38 -96
  38. data/ruhoh.gemspec +29 -10
  39. data/scaffolds/draft.html +9 -0
  40. data/scaffolds/page.html +0 -2
  41. data/scaffolds/post.html +0 -4
  42. data/scaffolds/theme/{images → javascripts}/.gitkeep +0 -0
  43. data/scaffolds/theme/layouts/default.html +2 -4
  44. data/scaffolds/theme/layouts/page.html +1 -1
  45. data/scaffolds/theme/layouts/post.html +1 -1
  46. data/scaffolds/theme/{css/style.css → media/.gitkeep} +0 -0
  47. data/scaffolds/theme/stylesheets/style.css +0 -0
  48. data/scaffolds/theme/theme.yml +27 -0
  49. data/scaffolds/theme/widgets/.gitkeep +0 -0
  50. data/spec/config_spec.rb +50 -0
  51. data/spec/db_spec.rb +28 -14
  52. data/spec/page_spec.rb +24 -35
  53. data/spec/parsers/layouts_spec.rb +5 -13
  54. data/spec/parsers/pages_spec.rb +13 -11
  55. data/spec/parsers/posts_spec.rb +34 -29
  56. data/spec/parsers/routes_spec.rb +2 -1
  57. data/spec/parsers/site_spec.rb +6 -5
  58. data/spec/setup_spec.rb +3 -47
  59. data/widgets/analytics/config.yml +5 -0
  60. data/{system_partials/analytics/getclicky → widgets/analytics/layouts/getclicky.html} +2 -2
  61. data/{system_partials/analytics/google → widgets/analytics/layouts/google.html} +1 -1
  62. data/widgets/comments/config.yml +12 -0
  63. data/{system_partials/comments/disqus → widgets/comments/layouts/disqus.html} +2 -2
  64. data/{system_partials/comments/facebook → widgets/comments/layouts/facebook.html} +1 -1
  65. data/{system_partials/comments/intensedebate → widgets/comments/layouts/intensedebate.html} +1 -1
  66. data/{system_partials/comments/livefyre → widgets/comments/layouts/livefyre.html} +1 -1
  67. data/widgets/google_prettify/config.yml +1 -0
  68. data/widgets/google_prettify/layouts/google_prettify.html +10 -0
  69. metadata +54 -31
  70. data/lib/ruhoh/templaters/base.rb +0 -57
  71. data/system_partials/syntax/google_prettify +0 -11
@@ -0,0 +1,75 @@
1
+ class Ruhoh
2
+ # Structured container for all paths to relevant directories and files in the system.
3
+ # Paths are based on the ruhohspec for the Universal Blog API.
4
+ # Additionally we store some system (gem) level paths for cascading to default functionality,
5
+ # such as default widgets, default dashboard view, etc.
6
+ module Paths
7
+ Paths = Struct.new(
8
+ :base,
9
+ :compiled,
10
+ :config_data,
11
+ :dashboard_file,
12
+ :media,
13
+ :pages,
14
+ :partials,
15
+ :plugins,
16
+ :posts,
17
+ :site_data,
18
+ :themes,
19
+ :widgets,
20
+
21
+ :theme,
22
+ :theme_config_data,
23
+ :theme_dashboard_file,
24
+ :theme_layouts,
25
+ :theme_media,
26
+ :theme_partials,
27
+ :theme_javascripts,
28
+ :theme_stylesheets,
29
+ :theme_widgets,
30
+
31
+ :system_dashboard_file,
32
+ :system_widgets
33
+ )
34
+
35
+ def self.generate(config, base)
36
+ paths = Paths.new
37
+ paths.base = base
38
+ paths.config_data = File.join(base, Ruhoh.names.config_data)
39
+ paths.pages = File.join(base, Ruhoh.names.pages)
40
+ paths.posts = File.join(base, Ruhoh.names.posts)
41
+ paths.partials = File.join(base, Ruhoh.names.partials)
42
+ paths.media = File.join(base, Ruhoh.names.media)
43
+ paths.widgets = File.join(base, Ruhoh.names.widgets)
44
+ paths.compiled = File.join(base, Ruhoh.names.compiled)
45
+ paths.dashboard_file = File.join(base, Ruhoh.names.dashboard_file)
46
+ paths.site_data = File.join(base, Ruhoh.names.site_data)
47
+ paths.themes = File.join(base, Ruhoh.names.themes)
48
+ paths.plugins = File.join(base, Ruhoh.names.plugins)
49
+
50
+ paths.theme = File.join(base, Ruhoh.names.themes, config.theme)
51
+ paths.theme_dashboard_file= File.join(paths.theme, Ruhoh.names.dashboard_file)
52
+ paths.theme_config_data = File.join(paths.theme, Ruhoh.names.theme_config)
53
+ paths.theme_layouts = File.join(paths.theme, Ruhoh.names.layouts)
54
+ paths.theme_stylesheets = File.join(paths.theme, Ruhoh.names.stylesheets)
55
+ paths.theme_javascripts = File.join(paths.theme, Ruhoh.names.javascripts)
56
+ paths.theme_media = File.join(paths.theme, Ruhoh.names.media)
57
+ paths.theme_widgets = File.join(paths.theme, Ruhoh.names.widgets)
58
+ paths.theme_partials = File.join(paths.theme, Ruhoh.names.partials)
59
+
60
+ return false unless self.theme_is_valid?(paths)
61
+
62
+ paths.system_dashboard_file = File.join(Ruhoh::Root, Ruhoh.names.dashboard_file)
63
+ paths.system_widgets = File.join(Ruhoh::Root, Ruhoh.names.widgets)
64
+
65
+ paths
66
+ end
67
+
68
+ def self.theme_is_valid?(paths)
69
+ return true if FileTest.directory?(paths.theme)
70
+ Ruhoh.log.error("Theme directory does not exist: #{paths.theme}")
71
+ return false
72
+ end
73
+
74
+ end #Paths
75
+ end #Ruhoh
@@ -14,8 +14,7 @@ class Ruhoh
14
14
 
15
15
  def call(env)
16
16
  return favicon if env['PATH_INFO'] == '/favicon.ico'
17
- dash = File.basename(Ruhoh.files.dashboard, File.extname(Ruhoh.files.dashboard))
18
- return admin if ["/#{dash}", "/#{dash}/"].include?(env['PATH_INFO'])
17
+ return admin if [Ruhoh.urls.dashboard, "#{Ruhoh.urls.dashboard}/"].include?(env['PATH_INFO'])
19
18
 
20
19
  id = Ruhoh::DB.routes[env['PATH_INFO']]
21
20
  raise "Page id not found for url: #{env['PATH_INFO']}" unless id
@@ -29,9 +28,16 @@ class Ruhoh
29
28
  end
30
29
 
31
30
  def admin
32
- system_dash = File.join(Ruhoh::Root, Ruhoh.files.dashboard)
33
- template = File.open(File.exist?(Ruhoh.paths.dashboard) ? Ruhoh.paths.dashboard : system_dash) {|f| f.read }
34
- output = Ruhoh::Templaters::Base.parse(template, nil)
31
+ template = nil
32
+ [
33
+ Ruhoh.paths.theme_dashboard_file,
34
+ Ruhoh.paths.dashboard_file,
35
+ Ruhoh.paths.system_dashboard_file
36
+ ].each do |path|
37
+ template = path and break if File.exist?(path)
38
+ end
39
+ template = File.open(template, 'r:UTF-8') {|f| f.read }
40
+ output = @page.templater.render(template, Ruhoh::DB.payload)
35
41
 
36
42
  [200, {'Content-Type' => 'text/html'}, [output]]
37
43
  end
data/lib/ruhoh/program.rb CHANGED
@@ -12,17 +12,48 @@ class Ruhoh
12
12
  # run Ruhoh::Program.preview
13
13
  #
14
14
  # Returns: A new Rack builder object which should work inside config.ru
15
- def self.preview(watch=true)
15
+ def self.preview(opts={})
16
+ opts[:watch] ||= true
17
+ opts[:env] ||= 'development'
18
+
16
19
  Ruhoh.setup
20
+ Ruhoh.config.env = opts[:env]
17
21
  Ruhoh::DB.update_all
18
- Ruhoh::Watch.start if watch
22
+ Ruhoh::Watch.start if opts[:watch]
19
23
  Rack::Builder.new {
20
24
  use Rack::Lint
21
25
  use Rack::ShowExceptions
22
- use Rack::Static, {:urls => ["/#{Ruhoh.folders.media}", "/#{Ruhoh.folders.templates}"]}
23
- run Ruhoh::Previewer.new(Ruhoh::Page.new)
26
+
27
+ # Serve base media
28
+ map Ruhoh.urls.media do
29
+ run Rack::File.new(Ruhoh.paths.media)
30
+ end
31
+
32
+ # Serve theme assets
33
+ map Ruhoh.urls.theme do
34
+ run Rack::File.new(Ruhoh.paths.theme)
35
+ end
36
+
37
+ # Serve widget javascripts
38
+ map Ruhoh.urls.widgets do
39
+ run Rack::File.new(Ruhoh.paths.widgets)
40
+ end
41
+
42
+ map '/' do
43
+ run Ruhoh::Previewer.new(Ruhoh::Page.new)
44
+ end
24
45
  }
25
46
  end
26
47
 
48
+ # Public: A program for compiling to a static website.
49
+ # The compile environment should always be 'production' in order
50
+ # to properly omit drafts and other development-only settings.
51
+ def self.compile(target)
52
+ Ruhoh.setup
53
+ Ruhoh.config.env = 'production'
54
+ Ruhoh::DB.update_all
55
+ Ruhoh::Compiler.compile(target)
56
+ end
57
+
27
58
  end #Program
28
59
  end #Ruhoh
@@ -0,0 +1,66 @@
1
+ class Ruhoh
2
+ module Templaters
3
+ module AssetHelpers
4
+
5
+ def assets
6
+ method = "assets_#{Ruhoh.config.env}"
7
+ return '' unless self.respond_to?(method)
8
+ self.__send__(method)
9
+ end
10
+
11
+ def assets_development
12
+ buffer = ''
13
+ master_layout = self.context['page']['master_layout']
14
+ sub_layout = self.context['page']['sub_layout']
15
+ stylesheets = Ruhoh::DB.stylesheets[master_layout] || []
16
+ stylesheets += Ruhoh::DB.stylesheets[sub_layout] || []
17
+ stylesheets += Ruhoh::DB.stylesheets[Ruhoh.names.widgets] || []
18
+ stylesheets.each do |style|
19
+ buffer += "<link href=\"#{style['url']}?#{rand()}\" type=\"text/css\" rel=\"stylesheet\" media=\"all\">\n"
20
+ end
21
+ buffer += "\n"
22
+ scripts = Ruhoh::DB.javascripts[master_layout] || []
23
+ scripts += Ruhoh::DB.javascripts[sub_layout] || []
24
+ scripts += Ruhoh::DB.javascripts[Ruhoh.names.widgets] || []
25
+ scripts.each do |script|
26
+ buffer += "<script src=\"#{script['url']}?#{rand()}\"></script>\n"
27
+ end
28
+
29
+ buffer
30
+ end
31
+
32
+ # TODO: Implement this for real.
33
+ def assets_production
34
+ self.assets_development
35
+ end
36
+
37
+ # NOTICE: This is unfinished and not-implemented!
38
+ def assets_production_not_implemented
39
+ buffer = ''
40
+ master_layout = self.context['page']['master_layout']
41
+ sub_layout = self.context['page']['sub_layout']
42
+ stylesheets = []
43
+ stylesheets << master_layout if Ruhoh::DB.stylesheets[master_layout]
44
+ stylesheets << sub_layout if Ruhoh::DB.stylesheets[sub_layout]
45
+
46
+ stylesheets.each do |name|
47
+ url = [Ruhoh.urls.theme_stylesheets, "#{name}.css"].join('/')
48
+ buffer += "<link href=\"#{url}\" type=\"text/css\" rel=\"stylesheet\" media=\"all\">\n"
49
+ end
50
+ buffer += "\n"
51
+
52
+ scripts = []
53
+ scripts << master_layout if Ruhoh::DB.javascripts[master_layout]
54
+ scripts << sub_layout if Ruhoh::DB.javascripts[sub_layout]
55
+ # Missing widgets
56
+ scripts.each do |name|
57
+ url = [Ruhoh.urls.theme_javascripts, "#{name}.js"].join('/')
58
+ buffer += "<script src=\"#{url}\"></script>\n"
59
+ end
60
+
61
+ buffer
62
+ end
63
+
64
+ end #AssetHelpers
65
+ end #Templaters
66
+ end #Ruhoh
@@ -0,0 +1,143 @@
1
+ class Ruhoh
2
+ module Templaters
3
+ module BaseHelpers
4
+
5
+ def partial(name)
6
+ p = Ruhoh::DB.partials[name.to_s]
7
+ Ruhoh::Friend.say { yellow "partial not found: '#{name}'" } if p.nil?
8
+ p
9
+ end
10
+
11
+ # Truncate the page content relative to a line_count limit.
12
+ # This is optimized for markdown files in which content is largely
13
+ # blocked into chunks and separating by blank lines.
14
+ # The line_limit truncates content based on # of content-based lines,
15
+ # so blank lines don't count toward the limit.
16
+ # Always break the content on a blank line only so result stays formatted nicely.
17
+ def summary
18
+ content, id = self.get_page_content
19
+ line_limit = self.context['site']['config']['posts']['summary_lines'].to_i rescue nil
20
+ line_limit ||= 20
21
+ line_count = 0
22
+ line_breakpoint = content.lines.count
23
+
24
+ content.lines.each_with_index do |line, i|
25
+ if line =~ /^\s*$/ # line with only whitespace
26
+ if line_count >= line_limit
27
+ line_breakpoint = i
28
+ break
29
+ end
30
+ else
31
+ line_count += 1
32
+ end
33
+ end
34
+
35
+ content = content.lines.to_a[0, line_breakpoint].join
36
+ content = self.render(content)
37
+ Ruhoh::Converter.convert(content, id)
38
+ end
39
+
40
+ def pages
41
+ pages = []
42
+ self.context['db']['pages'].each_value {|page| pages << page }
43
+ self.mark_active_page(pages)
44
+ end
45
+
46
+ def posts
47
+ self.to_posts(self.context['db']['posts']['chronological'])
48
+ end
49
+
50
+ def posts_latest
51
+ latest = self.context['site']['config']['posts']['latest'].to_i rescue nil
52
+ latest ||= 10
53
+ (latest.to_i > 0) ? self.posts[0, latest.to_i] : self.posts
54
+ end
55
+
56
+ def categories
57
+ cats = []
58
+ self.context['db']['posts']['categories'].each_value { |cat| cats << cat }
59
+ cats
60
+ end
61
+
62
+ def tags
63
+ tags = []
64
+ self.context['db']['posts']['tags'].each_value { |tag| tags << tag }
65
+ tags
66
+ end
67
+
68
+ def raw_code(sub_context)
69
+ code = sub_context.gsub('{', '&#123;').gsub('}', '&#125;').gsub('<', '&lt;').gsub('>', '&gt;')
70
+ "<pre><code>#{code}</code></pre>"
71
+ end
72
+
73
+ def debug(sub_context)
74
+ Ruhoh::Friend.say {
75
+ yellow "?debug:"
76
+ magenta sub_context.class
77
+ cyan sub_context.inspect
78
+ }
79
+
80
+ "<pre>#{sub_context.class}\n#{sub_context.pretty_inspect}</pre>"
81
+ end
82
+
83
+ def to_posts(sub_context)
84
+ Array(sub_context).map { |id|
85
+ self.context['db']['posts']['dictionary'][id]
86
+ }.compact
87
+ end
88
+
89
+ def to_pages(sub_context)
90
+ pages = Array(sub_context).map { |id|
91
+ self.context['db']['pages'][id]
92
+ }.compact
93
+ self.mark_active_page(pages)
94
+ end
95
+
96
+ def to_categories(sub_context)
97
+ Array(sub_context).map { |id|
98
+ self.context['db']['posts']['categories'][id]
99
+ }.compact
100
+ end
101
+
102
+ def to_tags(sub_context)
103
+ Array(sub_context).map { |id|
104
+ self.context['db']['posts']['tags'][id]
105
+ }.compact
106
+ end
107
+
108
+ def next(sub_context)
109
+ return unless sub_context.is_a?(String) || sub_context.is_a?(Hash)
110
+ id = sub_context.is_a?(Hash) ? sub_context['id'] : sub_context
111
+ return unless id
112
+ index = self.context['db']['posts']['chronological'].index(id)
113
+ return unless index && (index-1 >= 0)
114
+ next_id = self.context['db']['posts']['chronological'][index-1]
115
+ return unless next_id
116
+ self.to_posts(next_id)
117
+ end
118
+
119
+ def previous(sub_context)
120
+ return unless sub_context.is_a?(String) || sub_context.is_a?(Hash)
121
+ id = sub_context.is_a?(Hash) ? sub_context['id'] : sub_context
122
+ return unless id
123
+ index = self.context['db']['posts']['chronological'].index(id)
124
+ return unless index && (index+1 >= 0)
125
+ prev_id = self.context['db']['posts']['chronological'][index+1]
126
+ return unless prev_id
127
+ self.to_posts(prev_id)
128
+ end
129
+
130
+ # Marks the active page if exists in the given pages Array
131
+ def mark_active_page(pages)
132
+ pages.each_with_index do |page, i|
133
+ next unless page['id'] == self.context[:page]['id']
134
+ active_page = page.dup
135
+ active_page['is_active_page'] = true
136
+ pages[i] = active_page
137
+ end
138
+ pages
139
+ end
140
+
141
+ end #BaseHelpers
142
+ end #Templaters
143
+ end #Ruhoh
@@ -1,155 +1,8 @@
1
- require 'pp'
2
-
3
1
  class Ruhoh
4
2
  module Templaters
3
+ # Interface for user-defined helper methods
5
4
  module Helpers
6
-
7
- def partial(name)
8
- Ruhoh::DB.partials[name.to_s]
9
- end
10
-
11
- def pages
12
- pages = []
13
- self.context['db']['pages'].each_value {|page| pages << page }
14
- self.mark_active_page(pages)
15
- end
16
-
17
- def posts
18
- self.to_posts(self.context['db']['posts']['chronological'])
19
- end
20
-
21
- def categories
22
- cats = []
23
- self.context['db']['posts']['categories'].each_value { |cat| cats << cat }
24
- cats
25
- end
26
-
27
- def tags
28
- tags = []
29
- self.context['db']['posts']['tags'].each_value { |tag| tags << tag }
30
- tags
31
- end
32
-
33
- def raw_code(sub_context)
34
- code = sub_context.gsub('{', '&#123;').gsub('}', '&#125;').gsub('<', '&lt;').gsub('>', '&gt;')
35
- "<pre><code>#{code}</code></pre>"
36
- end
37
-
38
- def debug(sub_context)
39
- Ruhoh::Friend.say {
40
- yellow "?debug:"
41
- magenta sub_context.class
42
- cyan sub_context.inspect
43
- }
44
-
45
- "<pre>#{sub_context.class}\n#{sub_context.pretty_inspect}</pre>"
46
- end
47
-
48
- def to_posts(sub_context)
49
- Array(sub_context).map { |id|
50
- self.context['db']['posts']['dictionary'][id]
51
- }.compact
52
- end
53
-
54
- def to_pages(sub_context)
55
- pages = Array(sub_context).map { |id|
56
- self.context['db']['pages'][id]
57
- }.compact
58
- self.mark_active_page(pages)
59
- end
60
-
61
- def to_categories(sub_context)
62
- Array(sub_context).map { |id|
63
- self.context['db']['posts']['categories'][id]
64
- }.compact
65
- end
66
-
67
- def to_tags(sub_context)
68
- Array(sub_context).map { |id|
69
- self.context['db']['posts']['tags'][id]
70
- }.compact
71
- end
72
-
73
- def next(sub_context)
74
- return unless sub_context.is_a?(String) || sub_context.is_a?(Hash)
75
- id = sub_context.is_a?(Hash) ? sub_context['id'] : sub_context
76
- return unless id
77
- index = self.context['db']['posts']['chronological'].index(id)
78
- return unless index && (index-1 >= 0)
79
- next_id = self.context['db']['posts']['chronological'][index-1]
80
- return unless next_id
81
- self.to_posts(next_id)
82
- end
83
-
84
- def previous(sub_context)
85
- return unless sub_context.is_a?(String) || sub_context.is_a?(Hash)
86
- id = sub_context.is_a?(Hash) ? sub_context['id'] : sub_context
87
- return unless id
88
- index = self.context['db']['posts']['chronological'].index(id)
89
- return unless index && (index+1 >= 0)
90
- prev_id = self.context['db']['posts']['chronological'][index+1]
91
- return unless prev_id
92
- self.to_posts(prev_id)
93
- end
94
-
95
- def analytics
96
- return '' if self.context['page']['analytics'].to_s == 'false'
97
- analytics_config = self.context['site']['config']['analytics']
98
- return '' unless analytics_config && analytics_config['provider']
99
-
100
- if analytics_config['provider'] == "custom"
101
- code = self.partial("custom_analytics")
102
- else
103
- code = self.partial("analytics/#{analytics_config['provider']}")
104
- end
105
-
106
- return "<h2 style='color:red'>!Analytics Provider partial for '#{analytics_config['provider']}' not found </h2>" if code.nil?
107
-
108
- self.render(code)
109
- end
110
-
111
- def comments
112
- return '' if self.context['page']['comments'].to_s == 'false'
113
- comments_config = self.context['site']['config']['comments']
114
- return '' unless comments_config && comments_config['provider']
115
-
116
- if comments_config['provider'] == "custom"
117
- code = self.partial("custom_comments")
118
- else
119
- code = self.partial("comments/#{comments_config['provider']}")
120
- end
121
-
122
- return "<h2 style='color:red'>!Comments Provider partial for '#{comments_config['provider']}' not found </h2>" if code.nil?
123
-
124
- self.render(code)
125
- end
126
-
127
- def syntax
128
- syntax_config = self.context['site']['config']['syntax']
129
- return '' unless syntax_config && syntax_config['provider']
130
-
131
- if syntax_config['provider'] == "custom"
132
- code = self.partial("custom_syntax")
133
- else
134
- code = self.partial("syntax/#{syntax_config['provider']}")
135
- end
136
-
137
- return "<h2 style='color:red'>!Syntax Provider partial for '#{syntax_config['provider']}' not found </h2>" if code.nil?
138
5
 
139
- self.render(code)
140
- end
141
-
142
- # Marks the active page if exists in the given pages Array
143
- def mark_active_page(pages)
144
- pages.each_with_index do |page, i|
145
- next unless page['id'] == self.context[:page]['id']
146
- active_page = page.dup
147
- active_page['is_active_page'] = true
148
- pages[i] = active_page
149
- end
150
- pages
151
- end
152
-
153
6
  end #Helpers
154
7
  end #Templaters
155
8
  end #Ruhoh
@@ -1,8 +1,12 @@
1
- class Ruhoh
1
+ require 'ruhoh/templaters/base_helpers'
2
+ require 'ruhoh/templaters/asset_helpers'
3
+ require 'ruhoh/templaters/helpers'
2
4
 
5
+ class Ruhoh
3
6
  module Templaters
4
-
5
7
  class RMustache < Mustache
8
+ include Ruhoh::Templaters::BaseHelpers
9
+ include Ruhoh::Templaters::AssetHelpers
6
10
  include Ruhoh::Templaters::Helpers
7
11
 
8
12
  class RContext < Context
@@ -21,9 +25,46 @@ class Ruhoh
21
25
  def context
22
26
  @context ||= RContext.new(self)
23
27
  end
28
+
29
+ # Lazy-load the page body.
30
+ # When in a global scope (layouts, pages), the content is for the current page.
31
+ # May also be called in sub-contexts such as looping through posts.
32
+ #
33
+ # {{# posts }}
34
+ # {{{ content }}}
35
+ # {{/ posts }}
36
+ def content
37
+ content, id = self.get_page_content
38
+ content = self.render(content)
39
+ Ruhoh::Converter.convert(content, id)
40
+ end
41
+
42
+ def get_page_content
43
+ id = self.context['id']
44
+ id ||= self.context['page']['id']
45
+ return '' unless id
46
+ unless id =~ Regexp.new("^#{Ruhoh.names.posts}")
47
+ id = "#{Ruhoh.names.pages}/#{id}"
48
+ end
49
+
50
+ [Ruhoh::Utils.parse_page_file(Ruhoh.paths.base, id)['content'], id]
51
+ end
52
+
53
+ def widget(name)
54
+ return '' if self.context['page'][name.to_s].to_s == 'false'
55
+ Ruhoh::DB.widgets[name.to_s]['layout']
56
+ end
57
+
58
+ def method_missing(name, *args, &block)
59
+ return self.widget(name.to_s) if Ruhoh::DB.widgets.has_key?(name.to_s)
60
+ super
61
+ end
24
62
 
63
+ def respond_to?(method)
64
+ return true if Ruhoh::DB.widgets.has_key?(method.to_s)
65
+ super
66
+ end
67
+
25
68
  end #RMustache
26
-
27
69
  end #Templaters
28
-
29
70
  end #Ruhoh
data/lib/ruhoh/urls.rb ADDED
@@ -0,0 +1,46 @@
1
+ class Ruhoh
2
+ # Structured container for all pre-defined URLs in the system.
3
+ # These URLs are used primarily for static assets in development mode.
4
+ # When compiling, all urls are of course mapped literally to the asset filepaths.
5
+ module Urls
6
+ Urls = Struct.new(
7
+ :media,
8
+ :widgets,
9
+ :dashboard,
10
+ :theme,
11
+ :theme_media,
12
+ :theme_javascripts,
13
+ :theme_stylesheets,
14
+ :theme_widgets
15
+ )
16
+
17
+ def self.generate(config)
18
+ urls = Urls.new
19
+ urls.media = self.to_url(Ruhoh.names.assets, Ruhoh.names.media)
20
+ urls.widgets = self.to_url(Ruhoh.names.assets, Ruhoh.names.widgets)
21
+ urls.dashboard = self.to_url(Ruhoh.names.dashboard_file.split('.')[0])
22
+
23
+ urls.theme = self.to_url(Ruhoh.names.assets, config.theme)
24
+ urls.theme_media = self.to_url(Ruhoh.names.assets, config.theme, Ruhoh.names.media)
25
+ urls.theme_javascripts = self.to_url(Ruhoh.names.assets, config.theme, Ruhoh.names.javascripts)
26
+ urls.theme_stylesheets = self.to_url(Ruhoh.names.assets, config.theme, Ruhoh.names.stylesheets)
27
+ urls.theme_widgets = self.to_url(Ruhoh.names.assets, config.theme, Ruhoh.names.widgets)
28
+ urls
29
+ end
30
+
31
+ def self.to_url(*args)
32
+ args.unshift(nil).join('/')
33
+ end
34
+
35
+ def self.to_url_slug(title)
36
+ CGI::escape self.to_slug(title)
37
+ end
38
+
39
+ # My Post Title ===> my-post-title
40
+ def self.to_slug(title)
41
+ title = title.to_s.downcase.strip.gsub(/[^\p{Word}+]/u, '-')
42
+ title.gsub(/^\-+/, '').gsub(/\-+$/, '').gsub(/\-+/, '-')
43
+ end
44
+
45
+ end #Urls
46
+ end #Ruhoh