From b1d300718f626175fb157abfd6502fbe888c262f Mon Sep 17 00:00:00 2001 From: tdreyno Date: Thu, 15 Oct 2009 14:24:00 -0700 Subject: [PATCH] tests passing --- bin/mm-server | 57 +++------------ lib/middleman/base.rb | 65 +++++++++-------- lib/middleman/builder.rb | 6 +- lib/middleman/{features => }/compass.rb | 0 lib/middleman/features/cache_buster.rb | 20 +++--- lib/middleman/features/content_for.rb | 9 --- lib/middleman/features/minify_javascript.rb | 29 ++++---- lib/middleman/features/relative_assets.rb | 36 +++++----- lib/middleman/features/sprockets.rb | 39 ++++++----- lib/middleman/{features => }/haml.rb | 65 +---------------- lib/middleman/helpers.rb | 16 +++-- lib/middleman/rack/static.rb | 20 ++++++ lib/middleman/sass.rb | 70 +++++++++++++++++++ lib/middleman/templater+dynamic_renderer.rb | 2 + spec/cache_buster_spec.rb | 22 ++---- .../public/javascripts/empty-with-include.js | 1 - .../views/javascripts/empty-with-include.js | 1 + 17 files changed, 225 insertions(+), 233 deletions(-) rename lib/middleman/{features => }/compass.rb (100%) delete mode 100644 lib/middleman/features/content_for.rb rename lib/middleman/{features => }/haml.rb (53%) create mode 100644 lib/middleman/rack/static.rb create mode 100644 lib/middleman/sass.rb delete mode 100644 spec/fixtures/sample/public/javascripts/empty-with-include.js create mode 100644 spec/fixtures/sample/views/javascripts/empty-with-include.js diff --git a/bin/mm-server b/bin/mm-server index 582bb419..c719e5b4 100755 --- a/bin/mm-server +++ b/bin/mm-server @@ -2,16 +2,7 @@ require 'optparse' -# Require Middleman -require File.join(File.dirname(__FILE__), '..', 'lib', 'middleman') - -class Middleman::Base - set :root, Dir.pwd - set :logging, false - enable :static -end - -env = ENV['RACK_ENV'] || 'development' +env = ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development' options = { :Port => 4567, :Host => 'localhost', :AccessLog => [] } OptionParser.new { |opts| @@ -28,47 +19,21 @@ OptionParser.new { |opts| opts.parse! ARGV } -require 'rack' -require 'rack/utils' -require 'rack/request' -require 'rack/response' -require 'rack/showexceptions' - -module Middleman - class Static - def initialize(app, options={}) - @app = app - root = Middleman::Base.public - @file_server = Rack::File.new(root) - end - - def call(env) - path = env["PATH_INFO"] - if path.include?("favicon.ico") || File.exists?(File.join(Middleman::Base.public, path)) - @file_server.call(env) - else - @app.call(env) - end - end - end -end - -app_wrapper = lambda do |inner_app| - Rack::Builder.new { - use Rack::ShowExceptions - use Middleman::Static - run Middleman::Base - }.to_app -end - ENV['RACK_ENV'] = env +# Require Middleman +require File.join(File.dirname(__FILE__), '..', 'lib', 'middleman') + +class Middleman::Base + set :root, Dir.pwd + set :logging, false +end + require 'shotgun' -require 'thin' - config = File.join(File.dirname(__FILE__), '..', 'lib', 'middleman', 'config.ru') -app = Shotgun.new(config, app_wrapper) +app = Shotgun.new(config, lambda { |inner_app| Middleman::Base.new }) +require 'thin' Thin::Logging.silent = true Rack::Handler::Thin.run app, options do |inst| diff --git a/lib/middleman/base.rb b/lib/middleman/base.rb index 69a36913..fcd7a173 100644 --- a/lib/middleman/base.rb +++ b/lib/middleman/base.rb @@ -9,7 +9,7 @@ module Middleman set :app_file, __FILE__ set :root, Dir.pwd set :environment, ENV['MM_ENV'] || :development - set :supported_formats, ["erb"] + set :supported_formats, %w(erb) set :index_file, "index.html" set :js_dir, "javascripts" set :css_dir, "stylesheets" @@ -17,9 +17,28 @@ module Middleman set :build_dir, "build" set :http_prefix, "/" + require 'sinatra/content_for' + helpers Sinatra::ContentFor + + require 'middleman/helpers' + helpers Middleman::Helpers + + # Static files in public/ + enable :static + require 'middleman/rack/static' + use Middleman::Rack::Static + + @@features = [] + def self.enable(*opts) + @@features << opts + super + end + def self.disable(*opts) + @@features -= opts + super + end + # Features enabled by default - enable :compass - enable :content_for enable :sprockets # Features disabled by default @@ -66,26 +85,19 @@ module Middleman # This will match all requests not overridden in the project's init.rb not_found do self.class.init!(true, false) - + # Normalize the path and add index if we're looking at a directory path = request.path path << options.index_file if path.match(%r{/$}) path.gsub!(%r{^/}, '') - + # If the enabled renderers succeed, return the content, mime-type and an HTTP 200 if content = render_path(path) content_type media_type(File.extname(path)), :charset => 'utf-8' status 200 content else - # If no template handler renders the template, return the static file if it exists - path = File.join(options.public, request.path) - if !File.directory?(path) && File.exists?(path) - status 200 - send_file(path) - else - status 404 - end + status 404 end end @@ -94,31 +106,24 @@ module Middleman def self.init!(quiet=false, rerun=true) return if @@inited && !rerun - # Built-in helpers - require 'middleman/helpers' - helpers Middleman::Helpers - - # Haml is required & includes helpers - require "middleman/features/haml" - # Check for and evaluate local configuration local_config = File.join(self.root, "init.rb") if File.exists? local_config - puts "== Local config at: #{local_config}" unless quiet + puts "== Reading: Local config" unless quiet class_eval File.read(local_config) end - + # loop over enabled feature - features_path = File.expand_path("features/*.rb", File.dirname(__FILE__)) - Dir[features_path].each do |f| - feature_name = File.basename(f, '.rb') - option_name = :"#{feature_name}?" - if respond_to?(option_name) && send(option_name) === true - require "middleman/features/#{feature_name}" - end + @@features.flatten.each do |feature_name| + puts "== Enabling: #{feature_name.capitalize}" unless quiet + require "middleman/features/#{feature_name}" end @@inited = true end end -end \ No newline at end of file +end + +# Haml is required & includes helpers +require "middleman/haml" +require "middleman/sass" \ No newline at end of file diff --git a/lib/middleman/builder.rb b/lib/middleman/builder.rb index a2fcf5db..6b05d8c4 100644 --- a/lib/middleman/builder.rb +++ b/lib/middleman/builder.rb @@ -1,6 +1,5 @@ require 'templater' require 'middleman/templater+dynamic_renderer.rb' -require 'rack/test' # Use Rack::Test to access Sinatra without starting up a full server # Placeholder for any methods the builder needs to abstract to allow feature integration module Middleman @@ -37,9 +36,12 @@ module Middleman end def self.init! - glob! File.basename(Middleman::Base.public), Middleman::Base.supported_formats + glob! File.basename(Middleman::Base.public), [] glob! File.basename(Middleman::Base.views), Middleman::Base.supported_formats end + + def after_run + end end module Generators diff --git a/lib/middleman/features/compass.rb b/lib/middleman/compass.rb similarity index 100% rename from lib/middleman/features/compass.rb rename to lib/middleman/compass.rb diff --git a/lib/middleman/features/cache_buster.rb b/lib/middleman/features/cache_buster.rb index bf434677..7cb04e12 100644 --- a/lib/middleman/features/cache_buster.rb +++ b/lib/middleman/features/cache_buster.rb @@ -1,15 +1,13 @@ -class Middleman::Base +class << Middleman::Base alias_method :pre_cache_buster_asset_url, :asset_url - helpers do - def asset_url(path, prefix="") - http_path = pre_cache_buster_asset_url(path, prefix) - if http_path.include?("://") || !%w(.css .png .jpg .js .gif).include?(File.extname(http_path)) - http_path - else - real_path = File.join(self.class.environment == "build" ? options.build_dir : options.public, prefix, path) - http_path << "?" + File.mtime(real_path).strftime("%s") if File.readable?(real_path) - http_path - end + def asset_url(path, prefix="") + http_path = pre_cache_buster_asset_url(path, prefix) + if http_path.include?("://") || !%w(.css .png .jpg .js .gif).include?(File.extname(http_path)) + http_path + else + real_path = File.join(self.environment == "build" ? self.build_dir : self.public, prefix, path) + http_path << "?" + File.mtime(real_path).strftime("%s") if File.readable?(real_path) + http_path end end end \ No newline at end of file diff --git a/lib/middleman/features/content_for.rb b/lib/middleman/features/content_for.rb deleted file mode 100644 index f5a65613..00000000 --- a/lib/middleman/features/content_for.rb +++ /dev/null @@ -1,9 +0,0 @@ -begin - require 'sinatra/content_for' - - class Middleman::Base - helpers Sinatra::ContentFor - end -rescue LoadError - puts "Sinatra::ContentFor not available. Install it with: gem install sinatra-content-for" -end \ No newline at end of file diff --git a/lib/middleman/features/minify_javascript.rb b/lib/middleman/features/minify_javascript.rb index 3c8844cc..e59f24fd 100644 --- a/lib/middleman/features/minify_javascript.rb +++ b/lib/middleman/features/minify_javascript.rb @@ -12,20 +12,21 @@ module Middleman END end end + end - module StaticJavascript - def render_path(path) - if template_exists?(path, :js) - compressor = YUI::JavaScriptCompressor.new(:munge => true) - compressor.compress(super) - else - super - end + class Builder + alias_method :pre_yui_after_run, :after_run + def after_run + pre_yui_after_run + + compressor = ::YUI::JavaScriptCompressor.new(:munge => true) + Dir[File.join(Middleman::Base.build_dir, Middleman::Base.js_dir, "**", "*.js")].each do |path| + compressed_js = compressor.compress(File.read(path)) + File.open(path, 'w') { |f| f.write(compressed_js) } + say "<%= color('#{"[COMPRESSED]".rjust(12)}', :yellow) %> " + path.gsub(Middleman::Base.build_dir+"/", '') end end - end - - class Base - include Middleman::Minified::StaticJavascript - end -end \ No newline at end of file + end if Middleman::Base.environment == "build" +end + +Middleman::Base.supported_formats << "js" \ No newline at end of file diff --git a/lib/middleman/features/relative_assets.rb b/lib/middleman/features/relative_assets.rb index e638cfec..c33f22da 100644 --- a/lib/middleman/features/relative_assets.rb +++ b/lib/middleman/features/relative_assets.rb @@ -6,25 +6,25 @@ class Middleman::Base end end end - - helpers do - alias_method :pre_relative_asset_url, :asset_url - def asset_url(path, prefix="") - path = pre_relative_asset_url(path, prefix) - if path.include?("://") - path +end + +class << Middleman::Base + alias_method :pre_relative_asset_url, :asset_url + def asset_url(path, prefix="") + path = pre_relative_asset_url(path, prefix) + if path.include?("://") + path + else + path = path[1,path.length-1] if path[0,1] == '/' + request_path = request.path_info.dup + request_path << options.index_file if path.match(%r{/$}) + request_path.gsub!(%r{^/}, '') + parts = request_path.split('/') + + if parts.length > 1 + "../" * (parts.length - 1) + path else - path = path[1,path.length-1] if path[0,1] == '/' - request_path = request.path_info.dup - request_path << options.index_file if path.match(%r{/$}) - request_path.gsub!(%r{^/}, '') - parts = request_path.split('/') - - if parts.length > 1 - "../" * (parts.length - 1) + path - else - path - end + path end end end diff --git a/lib/middleman/features/sprockets.rb b/lib/middleman/features/sprockets.rb index 8e8cea2a..d04b5721 100644 --- a/lib/middleman/features/sprockets.rb +++ b/lib/middleman/features/sprockets.rb @@ -6,25 +6,30 @@ rescue LoadError end module Middleman - module Sprockets - def self.included(base) - base.supported_formats << "js" - end - - def render_path(path) - source = File.join(options.public, path) - if File.extname(path) == '.js' && File.exists?(source) - secretary = ::Sprockets::Secretary.new( :asset_root => options.public, - :source_files => [source] ) - # may need to rejigger since sprockets will only read views/ now - secretary.concatenation.to_s - else - super + module Rack + class Sprockets + def initialize(app, options={}) + @app = app + end + + def call(env) + path = env["PATH_INFO"] + source = File.join(Middleman::Base.views, path) + + if path.match(/\.js$/) && File.exists?(source) + secretary = ::Sprockets::Secretary.new( :root => Middleman::Base.root, + :source_files => [ File.join("views", path) ], + :load_path => [ File.join("public", Middleman::Base.js_dir), + File.join("views", Middleman::Base.js_dir) ]) + + [200, { "Content-Type" => "text/javascript" }, [secretary.concatenation.to_s]] + else + @app.call(env) + end end end end end -class Middleman::Base - include Middleman::Sprockets -end \ No newline at end of file +Middleman::Base.use Middleman::Rack::Sprockets +Middleman::Base.supported_formats << "js" \ No newline at end of file diff --git a/lib/middleman/features/haml.rb b/lib/middleman/haml.rb similarity index 53% rename from lib/middleman/features/haml.rb rename to lib/middleman/haml.rb index a28d7a7a..d5583adb 100644 --- a/lib/middleman/features/haml.rb +++ b/lib/middleman/haml.rb @@ -1,4 +1,4 @@ -require 'haml' +require "haml" module Middleman module Haml @@ -62,71 +62,8 @@ module Middleman end end end - - module Sass - def self.included(base) - base.supported_formats << "sass" - end - - def render_path(path) - if template_exists?(path, :sass) - begin - static_version = options.public + request.path_info - send_file(static_version) if File.exists? static_version - - location_of_sass_file = options.environment == "build" ? File.join(options.build_dir, options.css_dir) : "public" - css_filename = File.join(Dir.pwd, location_of_sass_file) + request.path_info - sass(path.to_sym, Compass.sass_engine_options.merge({ :css_filename => css_filename })) - rescue Exception => e - sass_exception_string(e) - end - else - super - end - end - - # Handle Sass errors - def sass_exception_string(e) - e_string = "#{e.class}: #{e.message}" - - if e.is_a? ::Sass::SyntaxError - e_string << "\non line #{e.sass_line}" - - if e.sass_filename - e_string << " of #{e.sass_filename}" - - if File.exists?(e.sass_filename) - e_string << "\n\n" - - min = [e.sass_line - 5, 0].max - begin - File.read(e.sass_filename).rstrip.split("\n")[ - min .. e.sass_line + 5 - ].each_with_index do |line, i| - e_string << "#{min + i + 1}: #{line}\n" - end - rescue - e_string << "Couldn't read sass file: #{e.sass_filename}" - end - end - end - end - < url) params = params.map { |k,v| %Q{#{k}="#{v}"}}.join(' ') %Q{#{title}} end - - def asset_url(path, prefix="") - base_url = File.join(options.http_prefix, prefix) - path.include?("://") ? path : File.join(base_url, path) - end def image_tag(path, params={}) params[:alt] ||= "" diff --git a/lib/middleman/rack/static.rb b/lib/middleman/rack/static.rb new file mode 100644 index 00000000..6357b899 --- /dev/null +++ b/lib/middleman/rack/static.rb @@ -0,0 +1,20 @@ +module Middleman + module Rack + class Static + def initialize(app, options={}) + @app = app + root = Middleman::Base.public + @file_server = ::Rack::File.new(root) + end + + def call(env) + path = env["PATH_INFO"] + if path.include?("favicon.ico") || File.exists?(File.join(Middleman::Base.public, path)) + @file_server.call(env) + else + @app.call(env) + end + end + end + end +end \ No newline at end of file diff --git a/lib/middleman/sass.rb b/lib/middleman/sass.rb new file mode 100644 index 00000000..34edb53e --- /dev/null +++ b/lib/middleman/sass.rb @@ -0,0 +1,70 @@ +require "sass" +require "middleman/compass" + +module Middleman + module Sass + def self.included(base) + base.supported_formats << "sass" + end + + def render_path(path) + if template_exists?(path, :sass) + begin + static_version = options.public + request.path_info + send_file(static_version) if File.exists? static_version + + location_of_sass_file = options.environment == "build" ? File.join(options.build_dir, options.css_dir) : "public" + css_filename = File.join(Dir.pwd, location_of_sass_file) + request.path_info + sass(path.to_sym, ::Compass.sass_engine_options.merge({ :css_filename => css_filename })) + rescue Exception => e + sass_exception_string(e) + end + else + super + end + end + + # Handle Sass errors + def sass_exception_string(e) + e_string = "#{e.class}: #{e.message}" + + if e.is_a? ::Sass::SyntaxError + e_string << "\non line #{e.sass_line}" + + if e.sass_filename + e_string << " of #{e.sass_filename}" + + if File.exists?(e.sass_filename) + e_string << "\n\n" + + min = [e.sass_line - 5, 0].max + begin + File.read(e.sass_filename).rstrip.split("\n")[ + min .. e.sass_line + 5 + ].each_with_index do |line, i| + e_string << "#{min + i + 1}: #{line}\n" + end + rescue + e_string << "Couldn't read sass file: #{e.sass_filename}" + end + end + end + end + < \ No newline at end of file