lib/vitrine.rb in vitrine-0.0.10 vs lib/vitrine.rb in vitrine-0.0.11
- old
+ new
@@ -1,8 +1,8 @@
require 'sinatra/base'
require 'coffee-script'
-#require 'coffee-script-source'
+require 'rack/contrib/try_static'
require 'sass'
require 'pathname'
require_relative 'version'
require_relative 'atomic_write'
@@ -82,25 +82,35 @@
set :static, true
set :show_exceptions, false
set :raise_errors, true
set :root, File.expand_path(File.dirname(__FILE__))
set :views, lambda { File.join(settings.root, "views") }
+ set :public_dir, lambda { File.join(settings.root, "public") }
-
-
# For extensionless things try to pick out the related templates
- # from the views directory, and render them with a default layout
+ # from the views directory, and render them with a default layout.
+ # If no template is found fallback to halting on 404
+ # so that Vitrine can be cascaded from.
get /^([^\.]+)$/ do | extensionless_path |
- render_template(extensionless_path)
+ render_template_or_static(extensionless_path)
end
-
# Allow "fake" form submits
post /^([^\.]+)$/ do | extensionless_path |
- render_template(extensionless_path)
+ render_template_or_static(extensionless_path)
end
+ def render_template_or_static(extensionless_path)
+ probable_html = extensionless_path + "/index.html"
+ html_path = File.join(settings.public_dir, probable_html)
+ if File.exist? html_path
+ send_file html_path
+ else
+ render_template(extensionless_path)
+ end
+ end
+
def render_template(extensionless_path)
# Find the related view
specific_view = extensionless_path + ".*"
view_index = extensionless_path + "/index.*"
@@ -111,27 +121,25 @@
# Glob for all the possibilites
possibilites = possible_globs.map do | pattern |
Dir.glob(File.join(settings.views, pattern))
end.flatten.reject do | e |
- e =~ /\.DS_Store/ # except DS_Store
- end.reject do | e |
- e =~ /(\.+)$/ # and except directory self-links
+ File.basename(e) =~ /^\./ # except invisibles and self-links
end
# Try the first template that has been found
template_path = possibilites.shift
# If nothing is found just bail
unless template_path
err = possible_globs.map{|e| e.inspect }.join(', ')
- raise "No template found - tried #{err}"
+ halt 404, "No template found - tried #{err}"
end
relative_path = Pathname.new(template_path).relative_path_from(Pathname.new(settings.views))
- $stderr.puts "-> #{extensionless_path.inspect} : Rendering via template #{relative_path.to_s.inspect}"
+ # $stderr.puts "-> #{extensionless_path.inspect} : Rendering via template #{relative_path.to_s.inspect}"
locals = {}
# Auto-pick the template engine out of the extension
template_engine = File.extname(template_path).gsub(/^\./, '')
render(template_engine, File.read(template_path), :layout => get_layout, :locals => locals)
@@ -142,17 +150,22 @@
get /(.+)\.css/ do | basename |
begin
content_type 'text/css', :charset => 'utf-8'
# TODO: has no handling for .sass
scss_source_path = File.join(settings.root, 'public', "#{basename}.scss")
- mtime_cache(scss_source_path) { Sass.compile_file(scss_source_path) }
+ mtime_cache(scss_source_path) do
+ Sass.compile_file(scss_source_path, cache_location: '/tmp/vitrine/sass-cache')
+ end
rescue Errno::ENOENT # Missing SCSS
halt 404, "No such CSS or SCSS file found"
rescue Exception => e # CSS syntax error or something alike
- # use smart CSS to inject an error message into the document
- 'body:before { color: red; font-size: 2em; content: %s }' % [e.class,
- "\n", "--> ", e.message].join.inspect
+ # Add a generated DOM element before <body/> to inject
+ # a visible error message
+ error_tpl = 'body:before { background: white; font-family: sans-serif; color: red; font-size: 14px; content: %s }'
+ css_message = error_tpl % [e.class, "\n", "--> ", e.message].join.inspect
+
+ halt 500, css_message
end
end
# Generate a sourcemap for CoffeeScript files
get /(.+)\.js\.map$/ do | basename |
@@ -163,29 +176,29 @@
Vitrine.build_coffeescript_source_map_body(coffee_source, File.join(settings.root, 'public'))
end
rescue Errno::ENOENT # Missing CoffeeScript
halt 404, "No coffeescript file found to generate the map for"
rescue Exception => e # CS syntax error or something alike
- # inject it into the document
- 'console.error(%s)' % [e.class, "\n", "--> ", e.message].join.inspect
+ halt 400, 'Compliation of the related CoffeeScript file failed'
end
end
# Try to find CoffeeScript replacement for missing JS
get /(.+)\.js$/ do | basename |
# If this file is not found resort back to a coffeescript
begin
coffee_source = File.join(settings.root, 'public', "#{basename}.coffee")
- content_type 'text/javascript', :charset => 'utf-8'
+ content_type 'text/javascript'
mtime_cache(coffee_source) do
["//# sourceMappingURL=#{basename}.js.map", CoffeeScript.compile(File.read(coffee_source))].join("\n")
end
rescue Errno::ENOENT # Missing CoffeeScript
halt 404, "No such JS file and could not find a .coffee replacement"
rescue Exception => e # CS syntax error or something alike
- # inject it into the document
- 'console.error(%s)' % [e.class, "\n", "--> ", e.message].join.inspect
+ # Inject the syntax error into the browser console
+ console_message = 'console.error(%s)' % [e.class, "\n", "--> ", e.message].join.inspect
+ halt 500, console_message
end
end
require 'fileutils'
@@ -197,17 +210,20 @@
cache_sha = Digest::SHA1.hexdigest(Marshal.dump(key))
# Store in a temp dir
FileUtils.mkdir_p '/tmp/vitrine'
p = '/tmp/vitrine/%s' % cache_sha
- begin
+ if File.exist?(p)
+ etag File.mtime(p)
File.read(p)
- rescue Errno::ENOENT => e
- Vitrine.atomic_write(p) do |f|
- $stderr.puts "---> Recompiling #{path} for #{request.path_info}"
- f.write(yield)
+ else
+ yield.tap do | body |
+ Vitrine.atomic_write(p) do |f|
+ # $stderr.puts "---> Recompiling #{path} for #{request.path_info}"
+ f.write body
+ end
+ etag File.mtime(p)
end
- retry
end
end
def get_layout
layouts = Dir.glob(File.join(settings.views, 'layout.*'))
\ No newline at end of file