ruhoh 1.1 → 2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/Gemfile +3 -3
  2. data/README.md +3 -2
  3. data/Rakefile +1 -22
  4. data/bin/ruhoh +1 -5
  5. data/history.json +16 -0
  6. data/lib/ruhoh.rb +229 -84
  7. data/lib/ruhoh/base/collection.rb +280 -0
  8. data/lib/ruhoh/base/compiler.rb +55 -0
  9. data/lib/ruhoh/base/model.rb +220 -0
  10. data/lib/ruhoh/base/model_view.rb +152 -0
  11. data/lib/ruhoh/base/watcher.rb +25 -0
  12. data/lib/ruhoh/cache.rb +46 -0
  13. data/lib/ruhoh/client.rb +162 -0
  14. data/lib/ruhoh/collections.rb +172 -0
  15. data/lib/ruhoh/console_methods.rb +21 -0
  16. data/lib/ruhoh/{converters/converter.rb → converter.rb} +4 -1
  17. data/lib/ruhoh/programs/compile.rb +22 -0
  18. data/lib/ruhoh/programs/preview.rb +63 -0
  19. data/lib/ruhoh/programs/watch.rb +45 -0
  20. data/lib/ruhoh/resources/dash/collection.rb +10 -0
  21. data/lib/ruhoh/resources/dash/model.rb +5 -0
  22. data/lib/ruhoh/resources/dash/model_view.rb +5 -0
  23. data/lib/ruhoh/resources/dash/previewer.rb +13 -0
  24. data/lib/ruhoh/resources/data/collection.rb +9 -0
  25. data/lib/ruhoh/resources/data/collection_view.rb +23 -0
  26. data/lib/ruhoh/resources/javascripts/collection.rb +9 -0
  27. data/lib/ruhoh/resources/javascripts/collection_view.rb +46 -0
  28. data/lib/ruhoh/resources/javascripts/compiler.rb +5 -0
  29. data/lib/ruhoh/resources/layouts/client.rb +45 -0
  30. data/lib/ruhoh/resources/layouts/model.rb +16 -0
  31. data/lib/ruhoh/resources/media/collection.rb +9 -0
  32. data/lib/ruhoh/resources/media/compiler.rb +27 -0
  33. data/lib/ruhoh/resources/pages/client.rb +124 -0
  34. data/lib/ruhoh/resources/pages/collection.rb +86 -0
  35. data/lib/ruhoh/resources/pages/collection_view.rb +73 -0
  36. data/lib/ruhoh/resources/pages/compiler.rb +101 -0
  37. data/lib/ruhoh/resources/pages/model.rb +5 -0
  38. data/lib/ruhoh/resources/pages/model_view.rb +5 -0
  39. data/lib/ruhoh/resources/pages/previewer.rb +72 -0
  40. data/lib/ruhoh/resources/partials/model.rb +11 -0
  41. data/lib/ruhoh/resources/stylesheets/collection.rb +9 -0
  42. data/lib/ruhoh/resources/stylesheets/collection_view.rb +45 -0
  43. data/lib/ruhoh/resources/stylesheets/compiler.rb +5 -0
  44. data/lib/ruhoh/resources/theme/collection.rb +14 -0
  45. data/lib/ruhoh/resources/theme/compiler.rb +54 -0
  46. data/lib/ruhoh/resources/widgets/collection.rb +26 -0
  47. data/lib/ruhoh/resources/widgets/collection_view.rb +34 -0
  48. data/lib/ruhoh/resources/widgets/compiler.rb +27 -0
  49. data/lib/ruhoh/resources/widgets/model.rb +16 -0
  50. data/lib/ruhoh/routes.rb +29 -0
  51. data/lib/ruhoh/utils.rb +32 -49
  52. data/lib/ruhoh/version.rb +2 -2
  53. data/lib/ruhoh/views/helpers/categories.rb +38 -0
  54. data/lib/ruhoh/views/helpers/paginator.rb +39 -0
  55. data/lib/ruhoh/views/helpers/tags.rb +37 -0
  56. data/lib/ruhoh/views/master_view.rb +183 -0
  57. data/lib/ruhoh/views/rmustache.rb +24 -0
  58. data/ruhoh.gemspec +6 -82
  59. data/spec/spec_helper.rb +1 -1
  60. data/spec/support/shared_contexts.rb +6 -5
  61. data/system/{scaffolds/post.html → _scaffold.html} +1 -1
  62. data/system/{dash.html → dash/index.html} +37 -51
  63. data/system/{scaffolds/layout.html → layouts/_scaffold.html} +0 -0
  64. data/system/layouts/paginator.html +28 -0
  65. data/system/plugins/sprockets/javascripts/compiler.rb +25 -0
  66. data/system/plugins/sprockets/javascripts/previewer.rb +17 -0
  67. data/system/plugins/sprockets/stylesheets/compiler.rb +26 -0
  68. data/system/plugins/sprockets/stylesheets/previewer.rb +17 -0
  69. data/system/widgets/analytics/{layouts/getclicky.html → getclicky.html} +6 -2
  70. data/system/widgets/analytics/{layouts/google.html → google.html} +5 -1
  71. data/system/widgets/comments/{layouts/disqus.html → disqus.html} +6 -2
  72. data/system/widgets/comments/{layouts/facebook.html → facebook.html} +9 -2
  73. data/system/widgets/comments/{layouts/intensedebate.html → intensedebate.html} +5 -1
  74. data/system/widgets/comments/{layouts/livefyre.html → livefyre.html} +5 -1
  75. data/system/widgets/google_prettify/{layouts/google_prettify.html → default.html} +6 -2
  76. metadata +69 -66
  77. data/lib/ruhoh/client/client.rb +0 -306
  78. data/lib/ruhoh/client/console_methods.rb +0 -9
  79. data/lib/ruhoh/client/help.yml +0 -56
  80. data/lib/ruhoh/compiler.rb +0 -72
  81. data/lib/ruhoh/compilers/rss.rb +0 -39
  82. data/lib/ruhoh/compilers/theme.rb +0 -46
  83. data/lib/ruhoh/config.rb +0 -62
  84. data/lib/ruhoh/db.rb +0 -50
  85. data/lib/ruhoh/deployers/s3.rb +0 -71
  86. data/lib/ruhoh/page.rb +0 -106
  87. data/lib/ruhoh/parsers/javascripts.rb +0 -55
  88. data/lib/ruhoh/parsers/layouts.rb +0 -32
  89. data/lib/ruhoh/parsers/pages.rb +0 -79
  90. data/lib/ruhoh/parsers/partials.rb +0 -42
  91. data/lib/ruhoh/parsers/payload.rb +0 -49
  92. data/lib/ruhoh/parsers/posts.rb +0 -259
  93. data/lib/ruhoh/parsers/routes.rb +0 -20
  94. data/lib/ruhoh/parsers/scaffolds.rb +0 -35
  95. data/lib/ruhoh/parsers/site.rb +0 -19
  96. data/lib/ruhoh/parsers/stylesheets.rb +0 -63
  97. data/lib/ruhoh/parsers/theme_config.rb +0 -30
  98. data/lib/ruhoh/parsers/widgets.rb +0 -104
  99. data/lib/ruhoh/paths.rb +0 -83
  100. data/lib/ruhoh/previewer.rb +0 -48
  101. data/lib/ruhoh/program.rb +0 -68
  102. data/lib/ruhoh/templaters/asset_helpers.rb +0 -66
  103. data/lib/ruhoh/templaters/base_helpers.rb +0 -147
  104. data/lib/ruhoh/templaters/helpers.rb +0 -8
  105. data/lib/ruhoh/templaters/rmustache.rb +0 -70
  106. data/lib/ruhoh/urls.rb +0 -50
  107. data/lib/ruhoh/watch.rb +0 -78
  108. data/spec/config_spec.rb +0 -50
  109. data/spec/db_spec.rb +0 -91
  110. data/spec/page_spec.rb +0 -164
  111. data/spec/parsers/layouts_spec.rb +0 -41
  112. data/spec/parsers/pages_spec.rb +0 -120
  113. data/spec/parsers/posts_spec.rb +0 -309
  114. data/spec/parsers/routes_spec.rb +0 -39
  115. data/spec/parsers/site_spec.rb +0 -28
  116. data/spec/setup_spec.rb +0 -12
  117. data/system/scaffolds/draft.html +0 -9
  118. data/system/scaffolds/page.html +0 -4
  119. data/system/widgets/analytics/config.yml +0 -5
  120. data/system/widgets/comments/config.yml +0 -13
  121. data/system/widgets/google_prettify/config.yml +0 -1
@@ -0,0 +1,46 @@
1
+ class Ruhoh
2
+ class Cache
3
+ def initialize(ruhoh)
4
+ @__cache = {}
5
+ end
6
+
7
+ def __cache
8
+ @__cache
9
+ end
10
+
11
+ def set(key, data)
12
+ key = tokenize(key)
13
+ return nil unless key
14
+
15
+ @__cache[key] = data
16
+ end
17
+
18
+ def get(key)
19
+ key = tokenize(key)
20
+ return nil unless key
21
+
22
+ if @__cache[key]
23
+ @__cache[key]
24
+ end
25
+ end
26
+
27
+ def delete(key)
28
+ @__cache.delete(tokenize(key))
29
+ end
30
+
31
+ private
32
+
33
+ def tokenize(key)
34
+ new_key = case key
35
+ when Hash
36
+ key.to_a.sort.to_s.strip
37
+ when Array
38
+ key.sort.to_s.strip
39
+ else
40
+ key.to_s.strip
41
+ end
42
+
43
+ new_key.empty? ? nil : new_key
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,162 @@
1
+ require 'ruhoh/programs/compile'
2
+ require 'ruhoh/console_methods'
3
+ require 'irb'
4
+ require 'benchmark'
5
+
6
+ class Ruhoh
7
+
8
+ class Client
9
+ DefaultBlogScaffold = 'git://github.com/ruhoh/blog.git'
10
+ Help = [
11
+ {
12
+ "command" => "new <directory_path>",
13
+ "desc" => "Create a new blog directory based on the Ruhoh specification."
14
+ },
15
+ {
16
+ "command" => "compile",
17
+ "desc" => "Compile to static website."
18
+ },
19
+ {
20
+ "command" => "help",
21
+ "desc" => "Show this menu."
22
+ }
23
+ ]
24
+ def initialize(data)
25
+ @args = data[:args]
26
+ @options = data[:options]
27
+ @opt_parser = data[:opt_parser]
28
+ @ruhoh = Ruhoh.new
29
+ cmd = (@args[0] == 'new') ? 'blog' : (@args[0] || 'help')
30
+
31
+ @ruhoh.setup
32
+ @ruhoh.setup_paths
33
+
34
+ return __send__(cmd) if respond_to?(cmd)
35
+
36
+ Ruhoh::Friend.say {
37
+ yellow "-> Autoloading '#{cmd}' as pages collection"
38
+ } unless @ruhoh.collections.exists?(cmd)
39
+
40
+ collection = @ruhoh.collection(cmd)
41
+ client = collection.load_client(data)
42
+
43
+ Ruhoh::Friend.say {
44
+ red "method '#{data[:args][1]}' not found for #{client.class}"
45
+ exit
46
+ } unless @args[1] && client.respond_to?(@args[1])
47
+
48
+ client.__send__(@args[1])
49
+ end
50
+
51
+ # Thanks rails! https://github.com/rails/rails/blob/master/railties/lib/rails/commands/console.rb
52
+ def console
53
+ require 'pp'
54
+ Ruhoh::ConsoleMethods.env = @args[1]
55
+ IRB::ExtendCommandBundle.send :include, Ruhoh::ConsoleMethods
56
+
57
+ ARGV.clear # IRB throws an error otherwise.
58
+ IRB.start
59
+ end
60
+ alias_method :c, :console
61
+
62
+ # Show Client Utility help documentation.
63
+ def help
64
+ options = @opt_parser.help
65
+ resources = [{"methods" => Help}]
66
+ resources += @ruhoh.collections.all.map {|name|
67
+ collection = @ruhoh.collection(name)
68
+ next unless collection.client?
69
+ next unless collection.client.const_defined?(:Help)
70
+ {
71
+ "name" => name,
72
+ "methods" => collection.client.const_get(:Help)
73
+ }
74
+ }.compact
75
+
76
+ Ruhoh::Friend.say {
77
+ plain "Ruhoh is a nifty, modular static blog generator."
78
+ plain "It is the Universal Static Blog API."
79
+ plain "Visit http://www.ruhoh.com for complete usage and documentation."
80
+ plain ''
81
+ plain options
82
+ plain ''
83
+ plain 'Commands:'
84
+ plain ''
85
+ resources.each do |resource|
86
+ resource["methods"].each do |method|
87
+ if resource["name"]
88
+ green(" " + "#{resource["name"]} #{method["command"]}")
89
+ else
90
+ green(" " + method["command"])
91
+ end
92
+ plain(" "+ method["desc"])
93
+ end
94
+ end
95
+ }
96
+ end
97
+
98
+ # Public: Compile to static website.
99
+ def compile
100
+ puts Benchmark.measure {
101
+ Ruhoh::Program.compile(@args[1])
102
+ }
103
+ end
104
+
105
+ # Public: Create a new blog at the directory provided.
106
+ def blog
107
+ name = @args[1]
108
+ scaffold = @args.length > 2 ? @args[2] : DefaultBlogScaffold
109
+ useHg = @options.hg
110
+ Ruhoh::Friend.say {
111
+ red "Please specify a directory path."
112
+ plain " ex: ruhoh new the-blogist"
113
+ exit
114
+ } if name.nil?
115
+
116
+ target_directory = File.join(Dir.pwd, name)
117
+
118
+ Ruhoh::Friend.say {
119
+ red "#{target_directory} already exists."
120
+ plain " Specify another directory or `rm -rf` this directory first."
121
+ exit
122
+ } if File.exist?(target_directory)
123
+
124
+ Ruhoh::Friend.say {
125
+ plain "Trying this command:"
126
+
127
+ if useHg
128
+ cyan " hg clone #{scaffold} #{target_directory}"
129
+ success = system('hg', 'clone', scaffold, target_directory)
130
+ else
131
+ cyan " git clone #{scaffold} #{target_directory}"
132
+ success = system('git', 'clone', scaffold, target_directory)
133
+ end
134
+
135
+ if success
136
+ green "Success! Now do..."
137
+ cyan " cd #{target_directory}"
138
+ cyan " rackup -p9292"
139
+ cyan " http://localhost:9292"
140
+ else
141
+ red "Could not git clone blog scaffold. Please try it manually:"
142
+ cyan " git clone git://github.com/ruhoh/blog.git #{target_directory}"
143
+ end
144
+ }
145
+ end
146
+
147
+ def ask(message, valid_options)
148
+ if valid_options
149
+ answer = get_stdin("#{message} #{valid_options.to_s.gsub(/"/, '').gsub(/, /,'/')} ") while !valid_options.include?(answer)
150
+ else
151
+ answer = get_stdin(message)
152
+ end
153
+ answer
154
+ end
155
+
156
+ def get_stdin(message)
157
+ print message
158
+ STDIN.gets.chomp
159
+ end
160
+
161
+ end
162
+ end
@@ -0,0 +1,172 @@
1
+ module Ruhoh::Resources ; end
2
+ # Require all the resources
3
+ FileUtils.cd(File.join(File.dirname(__FILE__), 'base')) do
4
+ (Dir['*.rb'] + Dir[File.join('*', '*.rb')]).each do |f|
5
+ require File.join(File.dirname(__FILE__), 'base', f)
6
+ end
7
+ end
8
+ FileUtils.cd(File.join(File.dirname(__FILE__), 'resources')) do
9
+ Dir[File.join('**', '*.rb')].each do |f|
10
+ require File.join(File.dirname(__FILE__), 'resources', f)
11
+ end
12
+ end
13
+
14
+ class Ruhoh
15
+ class Collections
16
+ def initialize(ruhoh)
17
+ @ruhoh = ruhoh
18
+ @collections = {}
19
+ end
20
+
21
+ def collection(resource)
22
+ get_module_namespace_for(resource).const_get(:Collection)
23
+ end
24
+
25
+ def collection?(resource)
26
+ get_module_namespace_for(resource).const_defined?(:Collection)
27
+ end
28
+
29
+ # Load and cache a given resource collection.
30
+ # This allows you to work with single object instance and perform
31
+ # persistant mutations on it if necessary.
32
+ # Note the collection is always wrapped in its view.
33
+ # @returns[Class Instance] of the resource and class_name given.
34
+ def load(resource)
35
+ return @collections[resource] if @collections[resource]
36
+ instance = collection?(resource) ?
37
+ collection(resource).new(@ruhoh) :
38
+ Ruhoh::Base::Collection.new(@ruhoh)
39
+ instance.resource_name = resource
40
+ @collections[resource] = instance.load_collection_view
41
+ end
42
+
43
+ # Load the CollectionView class for this resource.
44
+ # Used primarily to as the plugin interface to include modules for mustache.
45
+ def self.load(resource)
46
+ get_module_namespace_for(resource).const_get(:CollectionView)
47
+ end
48
+
49
+ def all
50
+ (discover + registered).uniq
51
+ end
52
+
53
+ def base
54
+ Ruhoh::Base.constants.select{ |a|
55
+ Ruhoh::Base.const_get(a).class == Module
56
+ }.map{ |a|
57
+ a.to_s.downcase
58
+ }
59
+ end
60
+
61
+ def registered
62
+ self.class.registered
63
+ end
64
+
65
+ def self.registered
66
+ Ruhoh::Resources.constants.map{ |a| a.to_s.downcase }.delete_if{ |a| a == "pages" }
67
+ end
68
+
69
+ # discover all the resource mappings
70
+ def discover
71
+ FileUtils.cd(@ruhoh.base) {
72
+ return Dir['*'].select { |x|
73
+ File.directory?(x) && !["plugins", 'compiled'].include?(x)
74
+ }
75
+ }
76
+ end
77
+
78
+ def acting_as_pages
79
+ pool = discover
80
+ theme = @ruhoh.config['theme']['name'] rescue nil
81
+ pool.delete(theme)
82
+
83
+ pool.keep_if { |resource|
84
+ config = @ruhoh.config[resource]
85
+ if (config && config["use"])
86
+ config["use"] == "pages"
87
+ else
88
+ if resource == "pages"
89
+ true
90
+ else
91
+ !registered.include?(resource)
92
+ end
93
+ end
94
+ }
95
+ end
96
+
97
+ def exists?(name)
98
+ all.include?(name)
99
+ end
100
+ alias_method :exist?, :exists?
101
+
102
+ def paginator_urls
103
+ data = {}
104
+ all.each do |name|
105
+ paginator = load(name).config['paginator']['url'] rescue nil
106
+ next if paginator.nil? || paginator.empty?
107
+
108
+ data[name] = @ruhoh.to_url(paginator)
109
+ end
110
+
111
+ data
112
+ end
113
+
114
+ def url_endpoints
115
+ urls = {}
116
+ urls["base_path"] = @ruhoh.base_path
117
+
118
+ all.each do |name|
119
+ collection = load(name)
120
+ next unless collection.respond_to?(:url_endpoint)
121
+ urls[name] = @ruhoh.to_url(collection.url_endpoint)
122
+ end
123
+
124
+ urls
125
+ end
126
+
127
+ def url_endpoints_sorted
128
+ sorted_urls = url_endpoints.each.map {|k, v| {"name" => k, "url" => v} }
129
+ sorted_urls.sort { |a, b| b["url"].length <=> a["url"].length }
130
+ end
131
+
132
+ protected
133
+
134
+ # Load the registered resource else default to Pages if not configured.
135
+ # @returns[Constant] the resource's module namespace
136
+ def get_module_namespace_for(resource)
137
+ type = @ruhoh.config[resource]["use"] rescue nil
138
+
139
+ self.class.get_module_namespace_for(resource, type)
140
+ end
141
+
142
+ def self.get_module_namespace_for(resource, type=nil)
143
+ if type
144
+ if registered.include?(type)
145
+ Ruhoh::Resources.const_get(camelize(type))
146
+ elsif base.include?(type)
147
+ Ruhoh::Base.const_get(camelize(type))
148
+ else
149
+ klass = camelize(type)
150
+ Friend.say {
151
+ red "#{resource} resource set to use:'#{type}' in config.yml but Ruhoh::Resources::#{klass} does not exist."
152
+ }
153
+ abort
154
+ end
155
+ else
156
+ if registered.include?(resource)
157
+ Ruhoh::Resources.const_get(camelize(resource))
158
+ else
159
+ Ruhoh::Resources.const_get(:Pages)
160
+ end
161
+ end
162
+ end
163
+
164
+ def camelize(name)
165
+ self.class.camelize(name)
166
+ end
167
+
168
+ def self.camelize(name)
169
+ name.to_s.split('_').map {|a| a.capitalize}.join
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,21 @@
1
+ class Ruhoh
2
+ module ConsoleMethods
3
+ class << self
4
+ attr_accessor :env
5
+ end
6
+
7
+ def ruhoh
8
+ return @ruhoh if @ruhoh
9
+ @ruhoh = Ruhoh.new
10
+ @ruhoh.setup
11
+ @ruhoh.env = ConsoleMethods.env || 'development'
12
+ @ruhoh.setup_paths
13
+ @ruhoh
14
+ end
15
+
16
+ def reload!
17
+ @ruhoh = nil
18
+ self.ruhoh
19
+ end
20
+ end
21
+ end
@@ -1,4 +1,7 @@
1
- require 'ruhoh/converters/markdown'
1
+ # Require all the converters
2
+ Dir[File.join(File.dirname(__FILE__), 'converters', '*.rb')].each { |f|
3
+ require f
4
+ }
2
5
 
3
6
  class Ruhoh
4
7
  module Converter
@@ -0,0 +1,22 @@
1
+ class Ruhoh
2
+ module Program
3
+ # Public: A program for compiling to a static website.
4
+ # The compile environment should always be 'production' in order
5
+ # to properly omit drafts and other development-only settings.
6
+ def self.compile(target)
7
+ ruhoh = Ruhoh.new
8
+ ruhoh.setup
9
+ ruhoh.env = 'production'
10
+ ruhoh.setup_paths
11
+ ruhoh.setup_plugins
12
+
13
+ if target
14
+ ruhoh.paths.compiled = File.expand_path(target)
15
+ elsif ruhoh.config["compiled"]
16
+ ruhoh.paths.compiled = ruhoh.config["compiled"]
17
+ end
18
+
19
+ ruhoh.compile
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,63 @@
1
+ require 'ruhoh/programs/watch'
2
+ class Ruhoh
3
+ module Program
4
+ # Public: A program for running ruhoh as a rack application
5
+ # which renders singular pages via their URL.
6
+ #
7
+ # Examples
8
+ #
9
+ # In config.ru:
10
+ #
11
+ # require 'ruhoh'
12
+ # run Ruhoh::Program.preview
13
+ #
14
+ # Returns: A new Rack builder object which should work inside config.ru
15
+ def self.preview(opts={})
16
+ opts[:watch] ||= true
17
+ opts[:env] ||= 'development'
18
+
19
+ ruhoh = Ruhoh.new
20
+ ruhoh.setup
21
+ ruhoh.env = opts[:env]
22
+ ruhoh.setup_paths
23
+ ruhoh.setup_plugins unless opts[:enable_plugins] == false
24
+
25
+ # initialize the routes dictionary for all page resources.
26
+ ruhoh.routes.all
27
+
28
+ Ruhoh::Program.watch(ruhoh) if opts[:watch]
29
+ Rack::Builder.new {
30
+ use Rack::Lint
31
+ use Rack::ShowExceptions
32
+
33
+ # Url endpoints as registered by the resources.
34
+ # The urls are mapped to the resource's individual rack-compatable Previewer class.
35
+ # Note page-like resources (posts, pages) don't render uniform url endpoints,
36
+ # since presumably they define customized permalinks per singular resource.
37
+ # Page-like resources are handled the root mapping below.
38
+ ruhoh.collections.url_endpoints_sorted.each do |h|
39
+ # Omit base_path and theme because they are special use-cases.
40
+ next if %w{base_path theme}.include?(h["name"])
41
+ map h["url"] do
42
+ collection = ruhoh.collection(h["name"])
43
+ if collection.previewer?
44
+ run collection.load_previewer
45
+ else
46
+ run Rack::Cascade.new(
47
+ collection.paths.reverse.map { |path|
48
+ Rack::File.new(path)
49
+ }
50
+ )
51
+ end
52
+ end
53
+ end
54
+
55
+ # The generic Page::Previewer is used to render any/all page-like resources,
56
+ # since they likely have arbitrary urls based on permalink settings.
57
+ map '/' do
58
+ run Ruhoh::Resources::Pages::Previewer.new(ruhoh)
59
+ end
60
+ }
61
+ end
62
+ end
63
+ end