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