middleman-core 3.0.14 → 3.1.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/features/clean_build.feature +4 -5
  2. data/features/content_type.feature +43 -0
  3. data/features/data.feature +9 -4
  4. data/features/front-matter-neighbor.feature +151 -0
  5. data/features/queryable.feature +31 -0
  6. data/features/step_definitions/queryable_steps.rb +123 -0
  7. data/fixtures/content-type-app/config.rb +1 -0
  8. data/fixtures/content-type-app/source/.htaccess +1 -0
  9. data/fixtures/content-type-app/source/README +1 -0
  10. data/fixtures/content-type-app/source/images/blank.gif +0 -0
  11. data/fixtures/content-type-app/source/index.html +1 -0
  12. data/fixtures/content-type-app/source/javascripts/app.js +1 -0
  13. data/fixtures/content-type-app/source/override.html +5 -0
  14. data/fixtures/content-type-app/source/stylesheets/site.css +1 -0
  15. data/fixtures/frontmatter-neighbor-app/config.rb +0 -0
  16. data/fixtures/frontmatter-neighbor-app/source/front-matter-2.php.erb +2 -0
  17. data/fixtures/frontmatter-neighbor-app/source/front-matter-2.php.erb.frontmatter +4 -0
  18. data/fixtures/frontmatter-neighbor-app/source/front-matter-auto.erb +1 -0
  19. data/fixtures/frontmatter-neighbor-app/source/front-matter-auto.erb.frontmatter +4 -0
  20. data/fixtures/frontmatter-neighbor-app/source/front-matter-change.html.erb +1 -0
  21. data/fixtures/frontmatter-neighbor-app/source/front-matter-change.html.erb.frontmatter +4 -0
  22. data/fixtures/frontmatter-neighbor-app/source/front-matter-encoding.html.erb +1 -0
  23. data/fixtures/frontmatter-neighbor-app/source/front-matter-encoding.html.erb.frontmatter +5 -0
  24. data/fixtures/frontmatter-neighbor-app/source/json-front-matter-2.php.erb +2 -0
  25. data/fixtures/frontmatter-neighbor-app/source/json-front-matter-2.php.erb.frontmatter +4 -0
  26. data/fixtures/frontmatter-neighbor-app/source/json-front-matter-auto.erb +1 -0
  27. data/fixtures/frontmatter-neighbor-app/source/json-front-matter-auto.erb.frontmatter +4 -0
  28. data/fixtures/frontmatter-neighbor-app/source/json-front-matter.html.erb +1 -0
  29. data/fixtures/frontmatter-neighbor-app/source/json-front-matter.html.erb.frontmatter +4 -0
  30. data/fixtures/frontmatter-neighbor-app/source/raw-front-matter.html +1 -0
  31. data/fixtures/frontmatter-neighbor-app/source/raw-front-matter.html.frontmatter +4 -0
  32. data/fixtures/frontmatter-neighbor-app/source/raw-front-matter.php +1 -0
  33. data/fixtures/frontmatter-neighbor-app/source/raw-front-matter.php.frontmatter +4 -0
  34. data/fixtures/frontmatter-settings-neighbor-app/config.rb +4 -0
  35. data/fixtures/frontmatter-settings-neighbor-app/source/alternate_layout.html.erb +1 -0
  36. data/fixtures/frontmatter-settings-neighbor-app/source/alternate_layout.html.erb.frontmatter +3 -0
  37. data/fixtures/frontmatter-settings-neighbor-app/source/ignored.html.erb +1 -0
  38. data/fixtures/frontmatter-settings-neighbor-app/source/ignored.html.erb.frontmatter +3 -0
  39. data/fixtures/frontmatter-settings-neighbor-app/source/layouts/alternate.erb +3 -0
  40. data/fixtures/frontmatter-settings-neighbor-app/source/layouts/override.erb +2 -0
  41. data/fixtures/frontmatter-settings-neighbor-app/source/override_layout.html.erb +1 -0
  42. data/fixtures/frontmatter-settings-neighbor-app/source/override_layout.html.erb.frontmatter +3 -0
  43. data/fixtures/frontmatter-settings-neighbor-app/source/page_mentioned.html.erb +1 -0
  44. data/fixtures/frontmatter-settings-neighbor-app/source/page_mentioned.html.erb.frontmatter +3 -0
  45. data/fixtures/nested-data-app/config.rb +1 -0
  46. data/fixtures/nested-data-app/data/examples/test.yml +1 -0
  47. data/fixtures/nested-data-app/source/test.html.erb +1 -0
  48. data/fixtures/queryable-app/config.rb +0 -0
  49. data/fixtures/queryable-app/source/2010-08-08-test-document-file.html.markdown +8 -0
  50. data/fixtures/queryable-app/source/2010-08-09-another-test-document.html.markdown +10 -0
  51. data/fixtures/queryable-app/source/2011-12-26-some-test-document.html.markdown +6 -0
  52. data/fixtures/queryable-app/source/document_with_date_in_yaml.html.markdown +7 -0
  53. data/fixtures/queryable-app/source/document_without_date.html.markdown +7 -0
  54. data/lib/middleman-core/application.rb +52 -84
  55. data/lib/middleman-core/cli.rb +3 -2
  56. data/lib/middleman-core/cli/build.rb +5 -7
  57. data/lib/middleman-core/cli/bundler.rb +1 -1
  58. data/lib/middleman-core/cli/console.rb +46 -0
  59. data/lib/middleman-core/configuration.rb +235 -0
  60. data/lib/middleman-core/core_extensions.rb +0 -6
  61. data/lib/middleman-core/core_extensions/data.rb +34 -11
  62. data/lib/middleman-core/core_extensions/extensions.rb +31 -35
  63. data/lib/middleman-core/core_extensions/external_helpers.rb +7 -7
  64. data/lib/middleman-core/core_extensions/file_watcher.rb +1 -1
  65. data/lib/middleman-core/core_extensions/front_matter.rb +44 -38
  66. data/lib/middleman-core/core_extensions/rendering.rb +27 -21
  67. data/lib/middleman-core/core_extensions/request.rb +41 -73
  68. data/lib/middleman-core/core_extensions/routing.rb +7 -24
  69. data/lib/middleman-core/core_extensions/show_exceptions.rb +6 -8
  70. data/lib/middleman-core/extensions.rb +35 -0
  71. data/lib/middleman-core/logger.rb +9 -0
  72. data/lib/middleman-core/meta_pages.rb +93 -0
  73. data/lib/middleman-core/meta_pages/assets/config.css +36 -0
  74. data/lib/middleman-core/meta_pages/assets/glyphicons-halflings.png +0 -0
  75. data/lib/middleman-core/meta_pages/assets/jquery-1.8.2.min.js +2 -0
  76. data/lib/middleman-core/meta_pages/assets/jquery.details-1.6.min.js +6 -0
  77. data/lib/middleman-core/meta_pages/assets/meta.css +368 -0
  78. data/lib/middleman-core/meta_pages/assets/sitemap.css +635 -0
  79. data/lib/middleman-core/meta_pages/assets/sitemap.js +0 -0
  80. data/lib/middleman-core/meta_pages/config_setting.rb +39 -0
  81. data/lib/middleman-core/meta_pages/sitemap_resource.rb +52 -0
  82. data/lib/middleman-core/meta_pages/sitemap_tree.rb +73 -0
  83. data/lib/middleman-core/meta_pages/templates/config.html.erb +59 -0
  84. data/lib/middleman-core/meta_pages/templates/index.html.erb +21 -0
  85. data/lib/middleman-core/meta_pages/templates/sitemap.html.erb +31 -0
  86. data/lib/middleman-core/preview_server.rb +18 -7
  87. data/lib/middleman-core/profiling.rb +1 -1
  88. data/lib/middleman-core/renderers/erb.rb +5 -5
  89. data/lib/middleman-core/renderers/less.rb +3 -3
  90. data/lib/middleman-core/renderers/markdown.rb +10 -9
  91. data/lib/middleman-core/renderers/redcarpet.rb +16 -21
  92. data/lib/middleman-core/renderers/sass.rb +4 -5
  93. data/lib/middleman-core/renderers/slim.rb +4 -1
  94. data/lib/middleman-core/sitemap.rb +3 -3
  95. data/lib/middleman-core/sitemap/extensions/content_type.rb +16 -0
  96. data/lib/middleman-core/sitemap/extensions/on_disk.rb +2 -2
  97. data/lib/middleman-core/sitemap/extensions/proxies.rb +26 -16
  98. data/lib/middleman-core/sitemap/queryable.rb +148 -0
  99. data/lib/middleman-core/sitemap/resource.rb +14 -2
  100. data/lib/middleman-core/sitemap/store.rb +8 -7
  101. data/lib/middleman-core/step_definitions/builder_steps.rb +3 -0
  102. data/lib/middleman-core/step_definitions/server_steps.rb +6 -1
  103. data/lib/middleman-core/templates/default/source/layouts/layout.erb +1 -1
  104. data/lib/middleman-core/templates/extension/lib/lib.rb +17 -26
  105. data/lib/middleman-core/templates/html5/source/layouts/layout.erb +1 -1
  106. data/lib/middleman-core/templates/shared/Gemfile.tt +6 -1
  107. data/lib/middleman-core/util.rb +7 -5
  108. data/lib/middleman-core/version.rb +1 -1
  109. data/middleman-core.gemspec +1 -1
  110. metadata +126 -28
  111. data/lib/middleman-core/core_extensions/builder.rb +0 -17
  112. data/lib/middleman-core/core_extensions/ruby_encoding.rb +0 -25
  113. data/middleman-core-x86-mingw32.gemspec +0 -38
@@ -1,6 +1,7 @@
1
1
  # Built on Rack
2
2
  require "rack"
3
3
  require "rack/file"
4
+ require "rack/lint"
4
5
 
5
6
  module Middleman
6
7
  module CoreExtensions
@@ -36,15 +37,7 @@ module Middleman
36
37
  #
37
38
  # @private
38
39
  def reset!
39
- @app = nil
40
- end
41
-
42
- # The shared Rack instance being build
43
- #
44
- # @private
45
- # @return [Rack::Builder]
46
- def app
47
- @app ||= ::Rack::Builder.new
40
+ @rack_app = nil
48
41
  end
49
42
 
50
43
  # Get the static instance
@@ -73,19 +66,23 @@ module Middleman
73
66
  # @private
74
67
  # @return [Rack::Builder]
75
68
  def to_rack_app(&block)
76
- inner_app = inst(&block)
69
+ @rack_app ||= begin
70
+ app = ::Rack::Builder.new
71
+ app.use Rack::Lint
77
72
 
78
- (@middleware || []).each do |m|
79
- app.use(m[0], *m[1], &m[2])
80
- end
73
+ Array(@middleware).each do |klass, options, blockm|
74
+ app.use(klass, *options, &block)
75
+ end
81
76
 
82
- app.map("/") { run inner_app }
77
+ inner_app = inst(&block)
78
+ app.map("/") { run inner_app }
83
79
 
84
- (@mappings || []).each do |m|
85
- app.map(m[0], &m[1])
86
- end
80
+ Array(@mappings).each do |path, block|
81
+ app.map(path, &block)
82
+ end
87
83
 
88
- app
84
+ app
85
+ end
89
86
  end
90
87
 
91
88
  # Prototype app. Used in config.ru
@@ -152,37 +149,39 @@ module Middleman
152
149
  # Methods to be mixed-in to Middleman::Application
153
150
  module InstanceMethods
154
151
  # Backwards-compatibility with old request.path signature
155
- attr_reader :request
152
+ def request
153
+ Thread.current[:legacy_request]
154
+ end
156
155
 
157
156
  # Accessor for current path
158
157
  # @return [String]
159
- attr_reader :current_path
158
+ def current_path
159
+ Thread.current[:current_path]
160
+ end
160
161
 
161
162
  # Set the current path
162
163
  #
163
164
  # @param [String] path The new current path
164
165
  # @return [void]
165
166
  def current_path=(path)
166
- @current_path = path
167
- @request = ::Thor::CoreExt::HashWithIndifferentAccess.new({
167
+ Thread.current[:current_path] = path
168
+ Thread.current[:legacy_request] = ::Thor::CoreExt::HashWithIndifferentAccess.new({
168
169
  :path => path,
169
170
  :params => req ? ::Thor::CoreExt::HashWithIndifferentAccess.new(req.params) : {}
170
171
  })
171
172
  end
172
173
 
173
- def use(*args, &block); self.class.use(*args, &block); end
174
- def map(*args, &block); self.class.map(*args, &block); end
175
-
176
- # Rack env
177
- attr_accessor :env
174
+ delegate :use, :to => :"self.class"
175
+ delegate :map, :to => :"self.class"
178
176
 
179
177
  # Rack request
180
178
  # @return [Rack::Request]
181
- attr_accessor :req
182
-
183
- # Rack response
184
- # @return [Rack::Response]
185
- attr_accessor :res
179
+ def req
180
+ Thread.current[:req]
181
+ end
182
+ def req=(value)
183
+ Thread.current[:req] = value
184
+ end
186
185
 
187
186
  def call(env)
188
187
  dup.call!(env)
@@ -192,10 +191,9 @@ module Middleman
192
191
  #
193
192
  # @param env Rack environment
194
193
  def call!(env)
195
- self.env = env
196
194
  # Store environment, request and response for later
197
195
  self.req = req = ::Rack::Request.new(env)
198
- self.res = res = ::Rack::Response.new
196
+ res = ::Rack::Response.new
199
197
 
200
198
  logger.debug "== Request: #{env["PATH_INFO"]}"
201
199
 
@@ -225,7 +223,7 @@ module Middleman
225
223
  # @param [Rack::Response] res
226
224
  def process_request(env, req, res)
227
225
  start_time = Time.now
228
- @current_path = nil
226
+ current_path = nil
229
227
 
230
228
  request_path = URI.decode(env["PATH_INFO"].dup)
231
229
  if request_path.respond_to? :force_encoding
@@ -243,12 +241,11 @@ module Middleman
243
241
  return not_found(res, request_path) unless resource && !resource.ignored?
244
242
 
245
243
  # If this path is a binary file, send it immediately
246
- return send_file(resource.source_file, env, res) if resource.binary?
244
+ return send_file(resource, env) if resource.binary?
247
245
 
248
246
  current_path = resource.destination_path
249
247
 
250
- # Set a HTTP content type based on the request's extensions
251
- content_type(res, mime_type(resource.ext))
248
+ res['Content-Type'] = resource.content_type || 'text/plain'
252
249
 
253
250
  begin
254
251
  # Write out the contents of the page
@@ -275,17 +272,14 @@ module Middleman
275
272
  # @param [Symbol] type File extension
276
273
  # @param [String] value Mime type
277
274
  # @return [void]
278
- def mime_type(type, value=nil)
279
- return type if type.nil? || type.to_s.include?('/')
280
- return ::Rack::Mime.mime_type('.txt') if type.empty?
275
+ def mime_type(type, value)
281
276
  type = ".#{type}" unless type.to_s[0] == ?.
282
- return ::Rack::Mime.mime_type(type, nil) unless value
283
277
  ::Rack::Mime::MIME_TYPES[type] = value
284
278
  end
285
279
 
286
280
  # Halt request and return 404
287
281
  def not_found(res, path)
288
- res.status == 404
282
+ res.status = 404
289
283
  res.write "<html><body><h1>File Not Found</h1><p>#{path}</p></body>"
290
284
  res.finish
291
285
  end
@@ -293,40 +287,14 @@ module Middleman
293
287
  # Immediately send static file
294
288
  #
295
289
  # @param [String] path File to send
296
- def send_file(path, env, res)
297
- extension = File.extname(path)
298
- matched_mime = mime_type(extension)
299
- matched_mime = "application/octet-stream" if matched_mime.nil?
300
- content_type res, matched_mime
301
-
290
+ def send_file(resource, env)
302
291
  file = ::Rack::File.new nil
303
- file.path = path
292
+ file.path = resource.source_file
304
293
  response = file.serving(env)
305
- response[1]['Content-Encoding'] = 'gzip' if %w(.svgz).include?(extension)
294
+ response[1]['Content-Encoding'] = 'gzip' if %w(.svgz .gz).include?(resource.ext)
295
+ response[1]['Content-Type'] = resource.content_type || "application/octet-stream"
306
296
  halt response
307
297
  end
308
-
309
- # Set the content type for the current request
310
- #
311
- # @param [String] type Content type
312
- # @param [Hash] params
313
- # @return [void]
314
- def content_type(res, type, params={})
315
- return unless type
316
- default = params.delete :default
317
- mime_type = mime_type(type) || default
318
- throw "Unknown media type: %p" % type if mime_type.nil?
319
- mime_type = mime_type.dup
320
- unless params.include? :charset
321
- params[:charset] = params.delete('charset') || "utf-8"
322
- end
323
- params.delete :charset if mime_type.include? 'charset'
324
- unless params.empty?
325
- mime_type << (mime_type.include?(';') ? ', ' : ';')
326
- mime_type << params.map { |kv| kv.join('=') }.join(', ')
327
- end
328
- res['Content-Type'] = mime_type
329
- end
330
298
  end
331
299
  end
332
300
  end
@@ -2,22 +2,6 @@
2
2
  module Middleman
3
3
  module CoreExtensions
4
4
  module Routing
5
-
6
- # Setup extension
7
- class << self
8
-
9
- # Once registered
10
- def registered(app)
11
- # Include methods
12
- app.send :include, InstanceMethods
13
- end
14
-
15
- alias :included :registered
16
- end
17
-
18
- # Routing instance methods
19
- module InstanceMethods
20
-
21
5
  # Takes a block which allows many pages to have the same layout
22
6
  #
23
7
  # with_layout :admin do
@@ -28,12 +12,12 @@ module Middleman
28
12
  # @param [String, Symbol] layout_name
29
13
  # @return [void]
30
14
  def with_layout(layout_name, &block)
31
- old_layout = layout
15
+ old_layout = config[:layout]
32
16
 
33
- set :layout, layout_name
17
+ config[:layout] = layout_name
34
18
  instance_exec(&block) if block_given?
35
19
  ensure
36
- set :layout, old_layout
20
+ config[:layout] = old_layout
37
21
  end
38
22
 
39
23
  # The page method allows the layout to be set on a specific path
@@ -48,13 +32,13 @@ module Middleman
48
32
  blocks = Array(block)
49
33
 
50
34
  # Default layout
51
- opts[:layout] = layout if opts[:layout].nil?
35
+ opts[:layout] = config[:layout] if opts[:layout].nil?
52
36
 
53
37
  # If the url is a regexp
54
38
  if url.is_a?(Regexp) || url.include?("*")
55
39
 
56
40
  # Use the metadata loop for matching against paths at runtime
57
- sitemap.provides_metadata_for_path url do |url|
41
+ sitemap.provides_metadata_for_path(url) do |_|
58
42
  { :options => opts, :blocks => blocks }
59
43
  end
60
44
 
@@ -64,7 +48,7 @@ module Middleman
64
48
  # Normalized path
65
49
  url = '/' + Middleman::Util.normalize_path(url)
66
50
  if url.end_with?('/') || File.directory?(File.join(source_dir, url))
67
- url = File.join(url, index_file)
51
+ url = File.join(url, config[:index_file])
68
52
  end
69
53
 
70
54
  # Setup proxy
@@ -77,11 +61,10 @@ module Middleman
77
61
  end
78
62
 
79
63
  # Setup a metadata matcher for rendering those options
80
- sitemap.provides_metadata_for_path url do |url|
64
+ sitemap.provides_metadata_for_path(url) do |_|
81
65
  { :options => opts, :blocks => blocks }
82
66
  end
83
67
  end
84
- end
85
68
  end
86
69
  end
87
70
  end
@@ -11,21 +11,19 @@ module Middleman
11
11
 
12
12
  # Once registered
13
13
  def registered(app)
14
+ # Whether to catch and display exceptions
15
+ # @return [Boolean]
16
+ app.config.define_setting :show_exceptions, true, 'Whether to catch and display exceptions'
17
+
14
18
  # When in dev
15
19
  app.configure :development do
16
20
  # Include middlemare
17
- if show_exceptions
18
- use ::Middleman::CoreExtensions::ShowExceptions::Middleware
21
+ if config[:show_exceptions]
22
+ use ::Rack::ShowExceptions
19
23
  end
20
24
  end
21
25
  end
22
26
  end
23
-
24
- # Custom exception class
25
- # TODO: Style this ourselves
26
- class Middleware < ::Rack::ShowExceptions
27
- end
28
-
29
27
  end
30
28
  end
31
29
  end
@@ -100,4 +100,39 @@ module Middleman
100
100
  File.exists?(full_path)
101
101
  end
102
102
  end
103
+
104
+ class Extension
105
+ class << self
106
+ def config
107
+ @_config ||= ::Middleman::Configuration::ConfigurationManager.new
108
+ end
109
+
110
+ def option(key, default=nil, description=nil)
111
+ config.define_setting(key, default, description)
112
+ end
113
+ end
114
+
115
+ attr_accessor :app, :options
116
+
117
+ def initialize(klass, options_hash={})
118
+ @options = self.class.config.dup
119
+ @options.finalize!
120
+
121
+ options_hash.each do |k, v|
122
+ @options[k] = v
123
+ end
124
+
125
+ yield @options if block_given?
126
+
127
+ ext = self
128
+ klass.after_configuration do
129
+ ext.app = self
130
+ ext.after_configuration
131
+ end
132
+ end
133
+
134
+ def after_configuration
135
+ nil
136
+ end
137
+ end
103
138
  end
@@ -1,5 +1,6 @@
1
1
  # Use the Ruby/Rails logger
2
2
  require 'active_support/core_ext/logger'
3
+ require 'thread'
3
4
 
4
5
  module Middleman
5
6
 
@@ -16,6 +17,14 @@ module Middleman
16
17
  if @instrumenting != false
17
18
  ::ActiveSupport::Notifications.subscribe(/\.middleman$/, self)
18
19
  end
20
+
21
+ @mutex = Mutex.new
22
+ end
23
+
24
+ def add(*args)
25
+ @mutex.synchronize do
26
+ super
27
+ end
19
28
  end
20
29
 
21
30
  def call(message, *args)
@@ -0,0 +1,93 @@
1
+ require 'rack/builder'
2
+ require 'rack/static'
3
+ require 'tilt'
4
+ require 'middleman-core/meta_pages/sitemap_tree'
5
+ require 'middleman-core/meta_pages/config_setting'
6
+
7
+ module Middleman
8
+ module MetaPages
9
+ # Metadata pages to be served in preview, in order to present information about the Middleman
10
+ # application and its configuration. Analogous to Firefox/Chrome's "about:" pages.
11
+ #
12
+ # Built using a ghetto little Rack web framework cobbled together because I didn't want to depend
13
+ # on Sinatra or figure out how to host Middleman inside Middleman.
14
+ class Application
15
+ def initialize(middleman)
16
+ # Hold a reference to the middleman application
17
+ @middleman = middleman
18
+
19
+ meta_pages = self
20
+ @rack_app = Rack::Builder.new do
21
+ # Serve assets from metadata/assets
22
+ use Rack::Static, :urls => ["/assets"], :root => File.join(File.dirname(__FILE__), 'meta_pages')
23
+
24
+ map '/' do
25
+ run meta_pages.method(:index)
26
+ end
27
+
28
+ map '/sitemap' do
29
+ run meta_pages.method(:sitemap)
30
+ end
31
+
32
+ map '/config' do
33
+ run meta_pages.method(:config)
34
+ end
35
+ end
36
+ end
37
+
38
+ def call(*args)
39
+ @rack_app.call(*args)
40
+ end
41
+
42
+ # The index page
43
+ def index(env)
44
+ template('index.html.erb')
45
+ end
46
+
47
+ # Inspect the sitemap
48
+ def sitemap(env)
49
+ resources = @middleman.inst.sitemap.resources(true)
50
+
51
+ sitemap_tree = SitemapTree.new
52
+
53
+ resources.each do |resource|
54
+ sitemap_tree.add_resource resource
55
+ end
56
+
57
+ template('sitemap.html.erb', :sitemap_tree => sitemap_tree)
58
+ end
59
+
60
+ # Inspect configuration
61
+ def config(env)
62
+ global_config = @middleman.inst.config.all_settings.map {|c| ConfigSetting.new(c) }
63
+ extension_config = Hash[@middleman.inst.extensions.map do |ext_name, extension|
64
+ opts = if extension.is_a?(::Middleman::Extension)
65
+ extension.options.all_settings.map {|c| ConfigSetting.new(c) }
66
+ else
67
+ nil
68
+ end
69
+ [ext_name, opts]
70
+ end]
71
+
72
+ template('config.html.erb',
73
+ :global_config => global_config,
74
+ :extension_config => extension_config,
75
+ :registered_extensions => Middleman::Extensions.registered.dup)
76
+ end
77
+
78
+ private
79
+
80
+ # Render a template with the given name and locals
81
+ def template(template_name, locals={})
82
+ template_path = File.join(File.dirname(__FILE__), 'meta_pages', 'templates', template_name)
83
+ content = Tilt.new(template_path).render(nil, locals)
84
+ response(content)
85
+ end
86
+
87
+ # Respond to an HTML request
88
+ def response(content)
89
+ [ 200, {"Content-Type" => "text/html"}, Array(content) ]
90
+ end
91
+ end
92
+ end
93
+ end