Revert "update docs"

This reverts commit 43ac01af5c.
This commit is contained in:
tdreyno 2009-10-22 17:25:15 -07:00
parent 43ac01af5c
commit 58d6fc94ea
49 changed files with 1372 additions and 0 deletions

20
LICENSE Normal file
View file

@ -0,0 +1,20 @@
Copyright (c) 2009 Thomas Reynolds
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

84
Rakefile Normal file
View file

@ -0,0 +1,84 @@
require 'rubygems'
require 'rake'
begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "middleman"
gem.summary = %Q{A static site generator utilizing Haml, Sass and providing YUI compression and cache busting}
gem.email = "tdreyno@gmail.com"
gem.homepage = "http://wiki.github.com/tdreyno/middleman"
gem.authors = ["Thomas Reynolds"]
gem.rubyforge_project = "middleman"
gem.executables = %w(mm-init mm-build mm-server)
gem.add_dependency("thin")
gem.add_dependency("shotgun")
gem.add_dependency("templater")
gem.add_dependency("sprockets")
gem.add_dependency("sinatra")
gem.add_dependency("sinatra-content-for")
gem.add_dependency("rack-test")
gem.add_dependency("yui-compressor")
gem.add_dependency("haml", ">=2.1.0")
gem.add_dependency("compass")
gem.add_development_dependency("rspec")
gem.add_development_dependency("sdoc")
end
Jeweler::RubyforgeTasks.new do |rubyforge|
rubyforge.doc_task = "rdoc"
end
Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
end
require 'spec/rake/spectask'
Spec::Rake::SpecTask.new(:spec) do |spec|
spec.libs << 'lib' << 'spec'
spec.spec_files = FileList['spec/**/*_spec.rb']
end
Spec::Rake::SpecTask.new(:rcov) do |spec|
spec.libs << 'lib' << 'spec'
spec.pattern = 'spec/**/*_spec.rb'
spec.rcov = true
end
task :spec => :check_dependencies
task :default => :spec
require 'rake/rdoctask'
require 'sdoc'
Rake::RDocTask.new do |rdoc|
if File.exist?('VERSION')
version = File.read('VERSION')
else
version = ""
end
# rdoc.template = 'direct'
rdoc.rdoc_dir = 'rdoc'
rdoc.title = "middleman #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('lib/middleman/features/sprockets+ruby19.rb')
rdoc.rdoc_files.exclude('lib/middleman/templater+dynamic_renderer.rb')
end
desc "Build and publish documentation using GitHub Pages."
task :pages do
if !`git status`.include?('nothing to commit')
abort "dirty index - not publishing!"
end
Rake::Task[:rerdoc].invoke
`git checkout gh-pages`
`ls -1 | grep -v rdoc | xargs rm -rf; mv rdoc/* .; rm -rf rdoc`
`git commit -a -m "update docs"; git push origin gh-pages`
`git checkout master`
end

1
VERSION Normal file
View file

@ -0,0 +1 @@
0.9.20

12
bin/mm-build Executable file
View file

@ -0,0 +1,12 @@
#!/usr/bin/env ruby
ENV['MM_ENV'] = "build"
# Require app
require File.join(File.dirname(__FILE__), "..", "lib", "middleman")
require 'middleman/builder'
#Middleman::Base.init!
Middleman::Builder.init!
Middleman::Generators.run_cli(Dir.pwd, 'mm-build', 1, %w(build --force).concat(ARGV))

36
bin/mm-init Executable file
View file

@ -0,0 +1,36 @@
#!/usr/bin/env ruby
require 'templater'
module Generators
extend Templater::Manifold
desc "Generator for streamlining staticmatic"
class NewSite < Templater::Generator
desc "Creates a new middleman scaffold."
first_argument :location, :required => true, :desc => "Project location"
option :css_dir, :desc => 'The path to the css files'
option :js_dir, :desc => 'The path to the javascript files'
option :images_dir, :desc => 'The path to the image files'
def destination_root
File.expand_path(location)
end
def self.source_root
File.join(File.dirname(__FILE__), '..', 'lib', 'middleman', 'template')
end
template :init, "init.rb"
glob! :views
glob! :public
empty_directory :stylesheets, "public/stylesheets"#, File.join("public", css_dir)
empty_directory :javascripts, "public/javascripts"#, File.join("public", js_dir)
empty_directory :images, "public/images"#, File.join("public", images_dir)
end
add :setup, NewSite
end
Generators.run_cli(Dir.pwd, 'mm-init', 1, %w(setup).concat(ARGV))

43
bin/mm-server Executable file
View file

@ -0,0 +1,43 @@
#!/usr/bin/env ruby
require 'optparse'
# Require Middleman
require File.join(File.dirname(__FILE__), '..', 'lib', 'middleman')
env = ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development'
options = { :Port => 4567, :AccessLog => [] }
OptionParser.new { |opts|
opts.banner = "Usage: mm-server [rack options]"
opts.separator ""
opts.separator "Rack options:"
opts.on("-p", "--port PORT", "use PORT (default: 4567)") { |port|
options[:Port] = port
}
opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e|
env = e
}
opts.on("--debug", "Debug mode") {
::Middleman::Base.set :logging, true
}
opts.parse! ARGV
}
ENV['RACK_ENV'] = env
class Middleman::Base
set :root, Dir.pwd
end
require 'shotgun'
config = File.join(File.dirname(__FILE__), '..', 'lib', 'middleman', 'config.ru')
app = Shotgun.new(config, lambda { |inner_app| Middleman::Base })
require 'thin'
Thin::Logging.silent = true
Rack::Handler::Thin.run app, options do |inst|
puts "== The Middleman is standing watch on port #{options[:Port]}"
end

7
deps.rip Normal file
View file

@ -0,0 +1,7 @@
git://github.com/jnicklas/templater.git
git://github.com/sstephenson/sprockets.git
git://github.com/sinatra/sinatra.git
git://github.com/nex3/haml.git
git://github.com/chriseppstein/compass.git
git://github.com/foca/sinatra-content-for.git
git://github.com/brynary/rack-test.git

4
lib/middleman.rb Normal file
View file

@ -0,0 +1,4 @@
libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
require 'middleman/base'

137
lib/middleman/base.rb Normal file
View file

@ -0,0 +1,137 @@
# Be nice to other library systems, like the wonderful Rip
require 'rubygems' unless ENV['NO_RUBYGEMS']
# We're riding on Sinatra, so let's include it
require 'sinatra/base'
module Middleman
class Base < Sinatra::Base
set :app_file, __FILE__
set :root, Dir.pwd
set :reload, false
set :logging, false
set :environment, ENV['MM_ENV'] || :development
set :supported_formats, %w(erb)
set :index_file, "index.html"
set :js_dir, "javascripts"
set :css_dir, "stylesheets"
set :images_dir, "images"
set :build_dir, "build"
set :http_prefix, "/"
use Rack::ConditionalGet if environment == :development
@@features = []
def self.enable(*opts)
@@features << opts
super
end
def self.disable(*opts)
@@features -= opts
super
end
# Rack helper for adding mime-types during local preview
def self.mime(ext, type)
ext = ".#{ext}" unless ext.to_s[0] == ?.
::Rack::Mime::MIME_TYPES[ext.to_s] = type
end
# Convenience function to discover if a tempalte exists for the requested renderer (haml, sass, etc)
def template_exists?(path, renderer=nil)
template_path = path.dup
template_path << ".#{renderer}" if renderer
File.exists? File.join(options.views, template_path)
end
# Base case renderer (do nothing), Should be over-ridden
module StaticRender
def render_path(path)
if template_exists?(path, :erb)
erb(path.to_sym)
else
false
end
end
end
include StaticRender
# This will match all requests not overridden in the project's init.rb
not_found do
# 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
status 404
end
end
end
end
# Haml is required & includes helpers
require "middleman/haml"
require "middleman/sass"
require 'sinatra/content_for'
require 'middleman/helpers'
require 'middleman/rack/static'
require 'middleman/rack/sprockets'
class Middleman::Base
helpers Sinatra::ContentFor
helpers Middleman::Helpers
use Middleman::Rack::Static
use Middleman::Rack::Sprockets
enable :compass
require "middleman/features/compass"
@@features -= [:compass]
# Features disabled by default
disable :slickmap
disable :cache_buster
disable :minify_css
disable :minify_javascript
disable :relative_assets
disable :maruku
disable :smush_pngs
# Default build features
configure :build do
enable :minify_css
enable :minify_javascript
enable :cache_buster
end
def self.new(*args, &bk)
# Check for and evaluate local configuration
local_config = File.join(self.root, "init.rb")
if File.exists? local_config
puts "== Reading: Local config" if logging?
class_eval File.read(local_config)
end
# loop over enabled feature
@@features.flatten.each do |feature_name|
next unless send(:"#{feature_name}?")
puts "== Enabling: #{feature_name.capitalize}" if logging?
require "middleman/features/#{feature_name}"
end
::Compass.configuration do |config|
config.http_images_path = self.http_images_path rescue File.join(self.http_prefix, self.images_dir)
config.http_stylesheets_path = self.http_css_path rescue File.join(self.http_prefix, self.css_dir)
end
super
end
end

53
lib/middleman/builder.rb Normal file
View file

@ -0,0 +1,53 @@
require 'templater'
require 'middleman/templater+dynamic_renderer.rb'
# Placeholder for any methods the builder needs to abstract to allow feature integration
module Middleman
class Builder < ::Templater::Generator
# Define source and desintation
def self.source_root; Dir.pwd; end
def destination_root; File.join(Dir.pwd, Middleman::Base.build_dir); end
# Override template to ask middleman for the correct extension to output
def self.template(name, *args, &block)
return if args[0].include?('layout')
args.first.split('/').each do |part|
return if part[0,1] == '_'
end
if (args[0] === args[1])
args[1] = args[0].gsub("#{File.basename(Middleman::Base.views)}/", "")
.gsub("#{File.basename(Middleman::Base.public)}/", "")
if File.extname(args[1]) != ".js"
args[1] = args[1].gsub!(File.extname(args[1]), "") if File.basename(args[1]).split('.').length > 2
end
end
super(name, *args, &block)
end
def self.file(name, *args, &block)
if (args[0] === args[1])
args[1] = args[0].gsub("#{File.basename(Middleman::Base.views)}/", "")
.gsub("#{File.basename(Middleman::Base.public)}/", "")
end
super(name, *args, &block)
end
def self.init!
glob! File.basename(Middleman::Base.public), []
glob! File.basename(Middleman::Base.views), Middleman::Base.supported_formats
end
def after_run
end
end
module Generators
extend ::Templater::Manifold
desc "Build a static site"
add :build, ::Middleman::Builder
end
end

2
lib/middleman/config.ru Normal file
View file

@ -0,0 +1,2 @@
require 'middleman'
run Middleman::Base

View file

@ -0,0 +1,18 @@
class << Middleman::Base
alias_method :pre_cache_buster_asset_url, :asset_url
def asset_url(path, prefix="", request=nil)
http_path = pre_cache_buster_asset_url(path, prefix, request)
if http_path.include?("://") || !%w(.css .png .jpg .js .gif).include?(File.extname(http_path))
http_path
else
begin
prefix = self.images_dir if prefix == self.http_images_path
rescue
end
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

View file

@ -0,0 +1,18 @@
class Middleman::Base
configure do
::Compass.configuration do |config|
images_location = (self.environment == "build") ? self.build_dir : self.public
config.project_path = Dir.pwd
config.sass_dir = File.join(File.basename(self.views), self.css_dir)
config.output_style = :nested
config.css_dir = File.join(File.basename(images_location), self.css_dir)
config.images_dir = File.join(File.basename(images_location), self.images_dir)
# File.expand_path(self.images_dir, self.public)
config.add_import_path(config.sass_dir)
end
::Compass.configure_sass_plugin!
end
end

View file

@ -0,0 +1,2 @@
# Errors to growl
# Build complete to growl

View file

@ -0,0 +1,39 @@
begin
require 'maruku'
rescue LoadError
puts "Maruku not available. Install it with: gem install maruku"
end
module Middleman
module Maruku
def self.included(base)
base.supported_formats << "maruku"
base.set :maruku, {}
end
def render_path(path)
if template_exists?(path, :maruku)
render :maruku, path.to_sym
else
super
end
end
private
def render_maruku(template, data, options, locals, &block)
maruku_src = render_erb(template, data, options, locals, &block)
instance = ::Maruku.new(maruku_src, options)
if block_given?
# render layout
instance.to_html_document
else
# render template
instance.to_html
end
end
end
class Base
include Middleman::Maruku
end
end

View file

@ -0,0 +1,9 @@
# Otherwise use YUI
# Fine a way to minify inline/css
class Middleman::Base
configure do
::Compass.configuration do |config|
config.output_style = :compressed
end
end
end

View file

@ -0,0 +1,35 @@
require "yui/compressor"
module Middleman
module Minified
module Javascript
include ::Haml::Filters::Base
def render_with_options(text, options)
compressor = ::YUI::JavaScriptCompressor.new(:munge => true)
data = compressor.compress(text)
<<END
<script type=#{options[:attr_wrapper]}text/javascript#{options[:attr_wrapper]}>#{data.chomp}</script>
END
end
end
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|
lines = IO.readlines(path)
if lines.length > 1
compressed_js = compressor.compress(lines.join($/))
File.open(path, 'w') { |f| f.write(compressed_js) }
say "<%= color('#{"[COMPRESSED]".rjust(12)}', :yellow) %> " + path.gsub(Middleman::Base.build_dir+"/", '')
end
end
end
end if Middleman::Base.environment == "build"
end
Middleman::Base.supported_formats << "js"

View file

@ -0,0 +1,30 @@
::Compass.configuration do |config|
config.relative_assets = true
end
class << Middleman::Base
alias_method :pre_relative_asset_url, :asset_url
def asset_url(path, prefix="", request=nil)
begin
prefix = self.images_dir if prefix == self.http_images_path
rescue
end
path = pre_relative_asset_url(path, prefix, request)
if path.include?("://")
path
else
path = path[1,path.length-1] if path[0,1] == '/'
request_path = request.path_info.dup
request_path << self.class.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
end
end
end

View file

@ -0,0 +1,119 @@
begin
require 'slickmap'
::Compass.configure_sass_plugin!
rescue LoadError
puts "Slickmap not available. Install it with: gem install compass-slickmap"
end
if Middleman::Base.environment == "build"
Middleman::Builder.template :slickmap, "sitemap.html", "sitemap.html"
end
Entry = Struct.new(:dir, :children)
class Middleman::Base
def build_sitemap(&block)
@@utility = []
[recurse_sitemap(Middleman::Base.views, &block), @@utility]
end
def recurse_sitemap(path, &block)
bad_ext = path.split('.html')[1]
path = path.gsub(bad_ext, '') if bad_ext
entry = Entry.new(path, [])
#no "." or ".." dirs
Dir[File.join(path, "*")].each do |e|
next if !File.directory?(e) && !e.include?(".html")
if File.directory?(e)
entry.children << recurse_sitemap(e, &block)
elsif block_given?
how_to_handle = block.call(e)
if how_to_handle == :valid
entry.children << recurse_sitemap(e, &block)
elsif how_to_handle == :utility
bad_ext = e.split('.html')[1]
e = e.gsub(bad_ext, '') if bad_ext
@@utility << e.gsub(Middleman::Base.views + "/", '')
end
end
end
entry
end
helpers do
def sitemap_node(n, first=false)
if n.children.length < 1
if !first && File.extname(n.dir).length > 0
haml_tag :li do
path = n.dir.gsub(self.class.views, '')
haml_concat link_to(File.basename(path), path)
end
end
else
haml_tag(:li, :id => first ? "home" : nil) do
if first
haml_concat link_to("Homepage", "/" + self.class.index_file)
else
# we are a dir
index = n.children.find { |c| c.dir.include?(self.class.index_file) }
haml_concat link_to(index.dir.gsub(self.class.views + "/", '').gsub("/" + File.basename(index.dir), '').capitalize, index.dir.gsub(self.class.views, ''))
end
other_children = n.children.select { |c| !c.dir.include?(self.class.index_file) }
if other_children.length > 0
if first
other_children.each { |i| sitemap_node(i) }
else
haml_tag :ul do
other_children.each { |i| sitemap_node(i) }
end
end
end
end
end
end
end
get '/sitemap.html' do
# Return :utility to put it util top menu. False to ignore
@tree, @utility = build_sitemap do |file_name|
:valid
end
haml :sitemap, :layout => false
end
use_in_file_templates!
end
__END__
@@ sitemap
!!!
%html{ :xmlns => "http://www.w3.org/1999/xhtml" }
%head
%meta{ :content => "text/html; charset=utf-8", "http-equiv" => "Content-type" }
%title Sitemap
%style{ :type => "text/css" }
:sass
@import slickmap.sass
+slickmap
:javascript
window.onload = function() {
document.getElementById('primaryNav').className = "col" + document.querySelectorAll("#primaryNav > li:not(#home)").length;
};
%body
.logo
%h1= @project_name || "Sitemap"
- if @project_subtitle
%h2= @project_subtitle
- if @utility.length > 0
%ul#utilityNav
- @utility.each do |u|
%li= link_to u, u
%ul#primaryNav
- sitemap_node(@tree, true)

View file

@ -0,0 +1,58 @@
require 'json'
require 'open-uri'
begin
require 'httpclient'
rescue LoadError
puts "httpclient not available. Install it with: gem install httpclient"
end
module Middleman
module SmushPngs
def self.included(base)
base.supported_formats << "png"
end
def render_path(file)
if File.extname(file) == ".png"
file = File.join(options.public, file)
optimized = optimized_image_data_for(file)
begin
raise "Error: got larger" if size(file) < optimized.size
raise "Error: empty file downloaded" if optimized.size < 20
optimized
rescue
File.read(file)
end
else
super
end
end
protected
def size(file)
File.exist?(file) ? File.size(file) : 0
end
def optimized_image_data_for(file)
# I leave these urls here, just in case it stops working again...
# url = "http://smush.it/ws.php" # original, redirects to somewhere else..
url = 'http://ws1.adq.ac4.yahoo.com/ysmush.it/ws.php'
# url = "http://developer.yahoo.com/yslow/smushit/ws.php" # official but does not work
# url = "http://smushit.com/ysmush.it/ws.php" # used at the new page but does not hande uploads
# url = "http://smushit.eperf.vip.ac4.yahoo.com/ysmush.it/ws.php" # used at the new page but does not hande uploads
response = HTTPClient.post url, { 'files[]' => File.new(file) }
response = JSON.parse(response.body.content)
raise "smush.it: #{response['error']}" if response['error']
image_url = response['dest']
raise "no dest path found" unless image_url
open(image_url) { |source| source.read() }
end
end
class Base
include Middleman::SmushPngs
end
end

69
lib/middleman/haml.rb Normal file
View file

@ -0,0 +1,69 @@
require "haml"
module Middleman
module Haml
module Renderer
def self.included(base)
base.supported_formats << "haml"
base.helpers Middleman::Haml::Helpers
end
def render_path(path)
if template_exists?(path, :haml)
result = nil
begin
result = haml(path.to_sym, :layout => File.extname(path) != ".xml")
rescue ::Haml::Error => e
result = "Haml Error: #{e}"
result << "<pre>Backtrace: #{e.backtrace.join("\n")}</pre>"
end
result
else
super
end
end
end
module Helpers
def haml_partial(name, options = {})
item_name = name.to_sym
counter_name = "#{name}_counter".to_sym
if collection = options.delete(:collection)
collection.enum_for(:each_with_index).collect do |item,index|
haml_partial name, options.merge(:locals => {item_name => item, counter_name => index+1})
end.join
elsif object = options.delete(:object)
haml_partial name, options.merge(:locals => {item_name => object, counter_name => nil})
else
haml "_#{name}".to_sym, options.merge(:layout => false)
end
end
end
module Table
include ::Haml::Filters::Base
def render(text)
output = '<div class="table"><table cellspacing="0" cellpadding="0">'
line_num = 0
text.each_line do |line|
line_num += 1
next if line.strip.empty?
output << %Q{<tr class="#{(line_num % 2 == 0) ? "even" : "odd" }#{(line_num == 1) ? " first" : "" }">}
columns = line.split("|").map { |p| p.strip }
columns.each_with_index do |col, i|
output << %Q{<td class="col#{i+1}">#{col}</td>}
end
output << "</tr>"
end
output + "</table></div>"
end
end
end
end
class Middleman::Base
include Middleman::Haml::Renderer
end

55
lib/middleman/helpers.rb Normal file
View file

@ -0,0 +1,55 @@
module Middleman
class Base
def self.asset_url(path, prefix="", request=nil)
base_url = File.join(self.http_prefix, prefix)
path.include?("://") ? path : File.join(base_url, path)
end
end
module Helpers
def page_classes(*additional)
path = request.path_info
path << options.index_file if path.match(%r{/$})
path.gsub!(%r{^/}, '')
classes = []
parts = path.split('.')[0].split('/')
parts.each_with_index { |path, i| classes << parts.first(i+1).join('_') }
classes << "index" if classes.empty?
classes += additional unless additional.empty?
classes.join(' ')
end
def asset_url(path, prefix="")
self.class.asset_url(path, prefix, request)
end
def link_to(title, url="#", params={})
params.merge!(:href => url)
params = params.map { |k,v| %Q{#{k}="#{v}"}}.join(' ')
%Q{<a #{params}>#{title}</a>}
end
def image_tag(path, params={})
params[:alt] ||= ""
prefix = options.http_images_path rescue options.images_dir
params = params.merge(:src => asset_url(path, prefix))
params = params.map { |k,v| %Q{#{k}="#{v}"}}.join(' ')
"<img #{params} />"
end
def javascript_include_tag(path, params={})
params = params.merge(:src => asset_url(path, options.js_dir), :type => "text/javascript")
params = params.map { |k,v| %Q{#{k}="#{v}"}}.join(' ')
"<script #{params}></script>"
end
def stylesheet_link_tag(path, params={})
params[:rel] ||= "stylesheet"
params = params.merge(:href => asset_url(path, options.css_dir), :type => "text/css")
params = params.map { |k,v| %Q{#{k}="#{v}"}}.join(' ')
"<link #{params} />"
end
end
end

View file

@ -0,0 +1,29 @@
module Sprockets
class SourceFile
def source_lines
@lines ||= begin
lines = []
comments = []
File.open(pathname.absolute_location, 'rb') do |file|
file.each do |line|
lines << line = SourceLine.new(self, line, file.lineno)
if line.begins_pdoc_comment? || comments.any?
comments << line
end
if line.ends_multiline_comment?
if line.ends_pdoc_comment?
comments.each { |l| l.comment! }
end
comments.clear
end
end
end
lines
end
end
end
end

View file

@ -0,0 +1,34 @@
begin
require 'sprockets'
require 'middleman/rack/sprockets+ruby19' # Sprockets ruby 1.9 duckpunch
rescue LoadError
puts "Sprockets not available. Install it with: gem install sprockets"
end
module Middleman
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
Middleman::Base.supported_formats << "js"

View file

@ -0,0 +1,21 @@
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"]
file_path = File.join(Middleman::Base.public, path)
if path.include?("favicon.ico") || (File.exists?(file_path) && !File.directory?(file_path))
@file_server.call(env)
else
@app.call(env)
end
end
end
end
end

70
lib/middleman/sass.rb Normal file
View file

@ -0,0 +1,70 @@
require "sass"
require '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
<<END
/*
#{e_string}
Backtrace:\n#{e.backtrace.join("\n")}
*/
body:before {
white-space: pre;
font-family: monospace;
content: "#{e_string.gsub('"', '\"').gsub("\n", '\\A ')}"; }
END
end
end
end
class Middleman::Base
include Middleman::Sass
end

View file

@ -0,0 +1,22 @@
<% if css_dir %>set :css_dir, "<%= css_dir -%>"<% end %>
<% if js_dir %>set :js_dir, "<%= js_dir -%>"<% end %>
<% if images_dir %>set :images_dir, "<%= images_dir -%>"<% end %>
# Helpers
helpers do
end
# Generic configuration
# enable :slickmap
# Build-specific configuration
configure :build do
# For example, change the Compass output style for deployment
# enable :minified_css
# Or use a different image path
# set :http_path, "/Content/images/"
# Disable cache buster
# disable :cache_buster
end

View file

@ -0,0 +1,4 @@
- content_for :head do
%title Custom head title
%h1 The Middleman is watching.

View file

@ -0,0 +1,7 @@
%html
%head
%title The Middleman!
= yield_content :head
%body
= yield

View file

@ -0,0 +1 @@
@import compass/reset.sass

View file

@ -0,0 +1,25 @@
require 'rack/test' # Use Rack::Test to access Sinatra without starting up a full server
# Monkey-patch to use a dynamic renderer
class Templater::Actions::File
def identical?
if exists?
return true if File.mtime(source) < File.mtime(destination)
FileUtils.identical?(source, destination)
else
false
end
end
end
class Templater::Actions::Template
def render
@render_cache ||= begin
# The default render just requests the page over Rack and writes the response
request_path = destination.gsub(File.join(Dir.pwd, Middleman::Base.build_dir), "")
browser = Rack::Test::Session.new(Rack::MockSession.new(Middleman::Base))
browser.get(request_path)
browser.last_response.body
end
end
end

134
middleman.gemspec Normal file
View file

@ -0,0 +1,134 @@
# Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{middleman}
s.version = "0.9.20"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Thomas Reynolds"]
s.date = %q{2009-10-22}
s.email = %q{tdreyno@gmail.com}
s.executables = ["mm-init", "mm-build", "mm-server"]
s.extra_rdoc_files = [
"LICENSE",
"README.rdoc"
]
s.files = [
".document",
".gitignore",
"LICENSE",
"README.rdoc",
"Rakefile",
"VERSION",
"bin/mm-build",
"bin/mm-init",
"bin/mm-server",
"deps.rip",
"lib/middleman.rb",
"lib/middleman/base.rb",
"lib/middleman/builder.rb",
"lib/middleman/config.ru",
"lib/middleman/features/cache_buster.rb",
"lib/middleman/features/compass.rb",
"lib/middleman/features/growl.rb",
"lib/middleman/features/maruku.rb",
"lib/middleman/features/minify_css.rb",
"lib/middleman/features/minify_javascript.rb",
"lib/middleman/features/relative_assets.rb",
"lib/middleman/features/slickmap.rb",
"lib/middleman/features/smush_pngs.rb",
"lib/middleman/haml.rb",
"lib/middleman/helpers.rb",
"lib/middleman/rack/sprockets+ruby19.rb",
"lib/middleman/rack/sprockets.rb",
"lib/middleman/rack/static.rb",
"lib/middleman/sass.rb",
"lib/middleman/template/init.rbt",
"lib/middleman/template/views/index.html.haml",
"lib/middleman/template/views/layout.html.haml",
"lib/middleman/template/views/stylesheets/site.css.sass",
"lib/middleman/templater+dynamic_renderer.rb",
"middleman.gemspec",
"spec/builder_spec.rb",
"spec/cache_buster_spec.rb",
"spec/fixtures/sample/init.rb",
"spec/fixtures/sample/public/javascripts/to-be-included.js",
"spec/fixtures/sample/public/static.html",
"spec/fixtures/sample/public/stylesheets/static.css",
"spec/fixtures/sample/views/_partial.haml",
"spec/fixtures/sample/views/index.html.haml",
"spec/fixtures/sample/views/inline-js.html.haml",
"spec/fixtures/sample/views/javascripts/empty-with-include.js",
"spec/fixtures/sample/views/layout.haml",
"spec/fixtures/sample/views/maruku.html.maruku",
"spec/fixtures/sample/views/services/index.html.haml",
"spec/fixtures/sample/views/stylesheets/site.css.sass",
"spec/generator_spec.rb",
"spec/relative_assets_spec.rb",
"spec/spec_helper.rb"
]
s.homepage = %q{http://wiki.github.com/tdreyno/middleman}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{middleman}
s.rubygems_version = %q{1.3.5}
s.summary = %q{A static site generator utilizing Haml, Sass and providing YUI compression and cache busting}
s.test_files = [
"spec/builder_spec.rb",
"spec/cache_buster_spec.rb",
"spec/fixtures/sample/init.rb",
"spec/generator_spec.rb",
"spec/relative_assets_spec.rb",
"spec/spec_helper.rb"
]
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<thin>, [">= 0"])
s.add_runtime_dependency(%q<shotgun>, [">= 0"])
s.add_runtime_dependency(%q<templater>, [">= 0"])
s.add_runtime_dependency(%q<sprockets>, [">= 0"])
s.add_runtime_dependency(%q<sinatra>, [">= 0"])
s.add_runtime_dependency(%q<sinatra-content-for>, [">= 0"])
s.add_runtime_dependency(%q<rack-test>, [">= 0"])
s.add_runtime_dependency(%q<yui-compressor>, [">= 0"])
s.add_runtime_dependency(%q<haml>, [">= 2.1.0"])
s.add_runtime_dependency(%q<compass>, [">= 0"])
s.add_development_dependency(%q<rspec>, [">= 0"])
s.add_development_dependency(%q<sdoc>, [">= 0"])
else
s.add_dependency(%q<thin>, [">= 0"])
s.add_dependency(%q<shotgun>, [">= 0"])
s.add_dependency(%q<templater>, [">= 0"])
s.add_dependency(%q<sprockets>, [">= 0"])
s.add_dependency(%q<sinatra>, [">= 0"])
s.add_dependency(%q<sinatra-content-for>, [">= 0"])
s.add_dependency(%q<rack-test>, [">= 0"])
s.add_dependency(%q<yui-compressor>, [">= 0"])
s.add_dependency(%q<haml>, [">= 2.1.0"])
s.add_dependency(%q<compass>, [">= 0"])
s.add_dependency(%q<rspec>, [">= 0"])
s.add_dependency(%q<sdoc>, [">= 0"])
end
else
s.add_dependency(%q<thin>, [">= 0"])
s.add_dependency(%q<shotgun>, [">= 0"])
s.add_dependency(%q<templater>, [">= 0"])
s.add_dependency(%q<sprockets>, [">= 0"])
s.add_dependency(%q<sinatra>, [">= 0"])
s.add_dependency(%q<sinatra-content-for>, [">= 0"])
s.add_dependency(%q<rack-test>, [">= 0"])
s.add_dependency(%q<yui-compressor>, [">= 0"])
s.add_dependency(%q<haml>, [">= 2.1.0"])
s.add_dependency(%q<compass>, [">= 0"])
s.add_dependency(%q<rspec>, [">= 0"])
s.add_dependency(%q<sdoc>, [">= 0"])
end
end

60
spec/builder_spec.rb Normal file
View file

@ -0,0 +1,60 @@
require 'fileutils'
describe "Builder" do
def project_file(*parts)
File.expand_path(File.join(File.dirname(__FILE__), "..", *parts))
end
before :all do
@root_dir = project_file("spec", "fixtures", "sample")
end
before :each do
build_cmd = project_file("bin", "mm-build")
`cd #{@root_dir} && #{build_cmd}`
end
after :each do
FileUtils.rm_rf(File.join(@root_dir, "build"))
end
it "should build haml files" do
File.exists?("#{@root_dir}/build/index.html").should be_true
File.read("#{@root_dir}/build/index.html").should include("<h1>Welcome</h1>")
end
xit "should build maruku files" do
File.exists?("#{@root_dir}/build/maruku.html").should be_true
File.read("#{@root_dir}/build/maruku.html").should include("<h1 class='header' id='hello_maruku'>Hello Maruku</h1>")
end
it "should build static files" do
File.exists?("#{@root_dir}/build/static.html").should be_true
File.read("#{@root_dir}/build/static.html").should include("Static, no code!")
end
it "should build subdirectory files" do
File.exists?("#{@root_dir}/build/services/index.html").should be_true
end
it "should build sass files" do
File.exists?("#{@root_dir}/build/stylesheets/site.css").should be_true
File.read("#{@root_dir}/build/stylesheets/site.css").should include("html,body,div,span,applet,object,iframe")
end
it "should build static css files" do
File.exists?("#{@root_dir}/build/stylesheets/static.css").should be_true
end
it "should not build partial files" do
File.exists?("#{@root_dir}/build/_partial.html").should be_false
end
it "should minify inline javascript" do
File.readlines("#{@root_dir}/build/inline-js.html").length.should == 9
end
it "should combine javascript" do
File.read("#{@root_dir}/build/javascripts/empty-with-include.js").should include("combo")
end
end

18
spec/cache_buster_spec.rb Normal file
View file

@ -0,0 +1,18 @@
require File.join(File.dirname(__FILE__), "spec_helper")
base = ::Middleman::Base
base.set :root, File.join(File.dirname(__FILE__), "fixtures", "sample")
describe "Cache Buster Feature" do
it "should not append query string if off" do
base.disable :cache_buster
base.new
base.asset_url("stylesheets/static.css").should_not include("?")
end
it "should append query string if on" do
base.enable :cache_buster
base.new
base.asset_url("stylesheets/static.css").should include("?")
end
end

1
spec/fixtures/sample/init.rb vendored Normal file
View file

@ -0,0 +1 @@
enable :maruku

View file

@ -0,0 +1 @@
function() { return "combo"; };

View file

@ -0,0 +1 @@
Static, no code!

View file

@ -0,0 +1,2 @@
body {
font-size: 12px; }

View file

@ -0,0 +1 @@
%p Test

View file

@ -0,0 +1 @@
%h1 Welcome

View file

@ -0,0 +1,7 @@
:javascript
;(function() {
this;
should();
all.be();
on = { one: line };
});

View file

@ -0,0 +1 @@
//= require <to-be-included>

View file

@ -0,0 +1,6 @@
%html
%head
%link{ :href => "/stylesheets/site.css", :rel => "stylesheet", :type => "text/css" }
%title My Sample Site
%body
= yield

View file

@ -0,0 +1 @@
# Hello Maruku {.header}

View file

@ -0,0 +1 @@
%h2 Services

View file

@ -0,0 +1 @@
@import compass/reset.sass

34
spec/generator_spec.rb Normal file
View file

@ -0,0 +1,34 @@
require 'fileutils'
describe "Generator" do
def project_file(*parts)
File.expand_path(File.join(File.dirname(__FILE__), "..", *parts))
end
before :all do
@root_dir = project_file("spec", "fixtures", "generator-test")
end
before :each do
init_cmd = project_file("bin", "mm-init")
`cd #{File.dirname(@root_dir)} && #{init_cmd} #{File.basename(@root_dir)}`
end
after :each do
FileUtils.rm_rf(@root_dir)
end
it "should copy template files" do
template_dir = project_file("lib", "template", "**/*")
Dir[template_dir].each do |f|
next if File.directory?(f)
File.exists?("#{@root_dir}/#{f.split('template/')[1]}").should be_true
end
end
it "should create empty directories" do
%w(views/stylesheets public/stylesheets public/javascripts public/images).each do |d|
File.exists?("#{@root_dir}/#{d}").should be_true
end
end
end

View file

@ -0,0 +1,28 @@
# require File.join(File.dirname(__FILE__), "spec_helper")
#
# base = ::Middleman::Base
# base.set :root, File.join(File.dirname(__FILE__), "fixtures", "sample")
#
# describe "Relative Assets Feature" do
# before do
# base.disable :relative_assets
# base.init!
# @app = base.new
# end
#
# it "should not contain ../ if off" do
# @app.asset_url("stylesheets/static.css").should_not include("?")
# end
# end
#
# describe "Relative Assets Feature" do
# before do
# base.enable :relative_assets
# base.init!
# @app = base.new
# end
#
# it "should contain ../ if on" do
# @app.asset_url("stylesheets/static.css").should include("?")
# end
# end

10
spec/spec_helper.rb Normal file
View file

@ -0,0 +1,10 @@
require 'rubygems'
require 'spec'
$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'middleman'
Spec::Runner.configure do |config|
end