sitemap works, tests pass

This commit is contained in:
Thomas Reynolds 2011-11-07 22:34:02 -08:00
parent 41a5d9bbee
commit b5561227f8
32 changed files with 305 additions and 250 deletions

View file

@ -1,6 +1,8 @@
2.1.pre 2.1.pre
==== ====
Finally support Compass in Sprockets! Thanks to @xdite and @petebrowne Finally support Compass in Sprockets! Thanks to @xdite and @petebrowne
Middleman::Sitemap object representing the known world
Middleman::FileWatcher proxies file change events
2.0.14 2.0.14
==== ====

View file

@ -15,15 +15,12 @@ Feature: Builder
Then "spaces in file.html" should exist at "test-app" and include "spaces" Then "spaces in file.html" should exist at "test-app" and include "spaces"
Then "images/Read me (example).txt" should exist at "test-app" Then "images/Read me (example).txt" should exist at "test-app"
Then "images/Child folder/regular_file(example).txt" should exist at "test-app" Then "images/Child folder/regular_file(example).txt" should exist at "test-app"
And cleanup built app at "test-app"
Scenario: Build glob Scenario: Build glob
Given a built app at "glob-app" with flags "--glob '**/*.sass'" Given a built app at "glob-app" with flags "--glob '*.css'"
Then "stylesheets/site.css" should exist at "glob-app" and include "html" Then "stylesheets/site.css" should exist at "glob-app" and include "html"
Then "index.html" should not exist at "glob-app" Then "index.html" should not exist at "glob-app"
And cleanup built app at "glob-app"
# Scenario: Force relative assets # Scenario: Force relative assets
# Given a built app at "relative-app" with flags "--relative" # Given a built app at "relative-app" with flags "--relative"
# Then "stylesheets/relative_assets.css" should exist at "relative-app" and include "../" # Then "stylesheets/relative_assets.css" should exist at "relative-app" and include "../"
# And cleanup built app at "relative-app"

View file

@ -7,4 +7,3 @@ Feature: Build Clean
Then "should_be_ignored.html" should not exist at "clean-app" Then "should_be_ignored.html" should not exist at "clean-app"
And "should_be_ignored2.html" should not exist at "clean-app" And "should_be_ignored2.html" should not exist at "clean-app"
And "should_be_ignored3.html" should not exist at "clean-app" And "should_be_ignored3.html" should not exist at "clean-app"
And cleanup built app at "clean-app"

View file

@ -11,7 +11,6 @@ Feature: Directory Index
Then "needs_index.html" should not exist at "indexable-app" Then "needs_index.html" should not exist at "indexable-app"
Then "a_folder/needs_index.html" should not exist at "indexable-app" Then "a_folder/needs_index.html" should not exist at "indexable-app"
Then "leave_me_alone/index.html" should not exist at "indexable-app" Then "leave_me_alone/index.html" should not exist at "indexable-app"
And cleanup built app at "indexable-app"
Scenario: Preview normal file Scenario: Preview normal file
Given the Server is running at "indexable-app" Given the Server is running at "indexable-app"

View file

@ -10,7 +10,6 @@ Feature: Dynamic Pages
Then "should_be_ignored.html" should not exist at "test-app" Then "should_be_ignored.html" should not exist at "test-app"
Then "should_be_ignored2.html" should not exist at "test-app" Then "should_be_ignored2.html" should not exist at "test-app"
Then "should_be_ignored3.html" should not exist at "test-app" Then "should_be_ignored3.html" should not exist at "test-app"
And cleanup built app at "test-app"
Scenario: Preview basic proxy Scenario: Preview basic proxy
Given the Server is running at "test-app" Given the Server is running at "test-app"

View file

@ -3,7 +3,6 @@ Feature: Web Fonts
Scenario: Checking built folder for content Scenario: Checking built folder for content
Given a built app at "fonts-app" Given a built app at "fonts-app"
Then "stylesheets/fonts.css" should exist at "fonts-app" and include "/fonts/StMarie-Thin.otf" Then "stylesheets/fonts.css" should exist at "fonts-app" and include "/fonts/StMarie-Thin.otf"
And cleanup built app at "fonts-app"
Scenario: Rendering scss Scenario: Rendering scss
Given the Server is running at "fonts-app" Given the Server is running at "fonts-app"

View file

@ -23,7 +23,6 @@ Feature: Sprockets
Scenario: Multiple engine files should build correctly Scenario: Multiple engine files should build correctly
Given a built app at "test-app" Given a built app at "test-app"
Then "javascripts/multiple_engines.js" should exist at "test-app" and include "Hello One" Then "javascripts/multiple_engines.js" should exist at "test-app" and include "Hello One"
And cleanup built app at "test-app"
Scenario: Sprockets CSS require //require Scenario: Sprockets CSS require //require
Given the Server is running at "test-app" Given the Server is running at "test-app"

View file

@ -11,6 +11,10 @@ end
Given /^a built app at "([^"]*)"$/ do |path| Given /^a built app at "([^"]*)"$/ do |path|
root = File.dirname(File.dirname(File.dirname(__FILE__))) root = File.dirname(File.dirname(File.dirname(__FILE__)))
target = File.join(root, "fixtures", path) target = File.join(root, "fixtures", path)
build_target = File.join(target, "build")
FileUtils.rm_rf(build_target)
build_cmd = File.expand_path(File.join(root, "bin", "middleman build")) build_cmd = File.expand_path(File.join(root, "bin", "middleman build"))
`cd #{target} && #{build_cmd}` `cd #{target} && #{build_cmd}`
end end

View file

@ -0,0 +1 @@
I am real

View file

@ -0,0 +1,5 @@
---
layout: false
---
I am real: one

View file

@ -0,0 +1,5 @@
---
layout: false
---
I am real: two

View file

@ -0,0 +1,12 @@
<html>
<head>
<title>My Sample Site</title>
<!-- Comment in layout -->
</head>
<body>
<h1>Welcome</h1>
<h2 id='h2'>H2</h2>
<p>Paragraph</p>
</body>
</html>

View file

@ -0,0 +1 @@
I am real

View file

@ -0,0 +1,5 @@
---
layout: false
---
I am real:

View file

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

View file

@ -0,0 +1 @@
<h1>Ignore me! 3</h1>

Binary file not shown.

View file

@ -0,0 +1,3 @@
@font-face {
font-family: "St Marie";
src: url('/fonts/StMarie-Thin.otf') format('opentype'); }

View file

@ -0,0 +1,46 @@
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline; }
body {
line-height: 1; }
ol, ul {
list-style: none; }
table {
border-collapse: collapse;
border-spacing: 0; }
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle; }
q, blockquote {
quotes: none; }
q:before, q:after, blockquote:before, blockquote:after {
content: "";
content: none; }
a img {
border: none; }
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary {
display: block; }

View file

@ -0,0 +1 @@
Indexable

View file

@ -0,0 +1 @@
Stay away

View file

@ -0,0 +1 @@
Indexable

View file

@ -0,0 +1 @@
Regular

View file

@ -62,7 +62,6 @@ require "sinatra/base"
module Middleman module Middleman
# Auto-load modules on-demand # Auto-load modules on-demand
autoload :Base, "middleman/base" autoload :Base, "middleman/base"
autoload :Sitemap, "middleman/sitemap"
autoload :Builder, "middleman/builder" autoload :Builder, "middleman/builder"
autoload :CLI, "middleman/cli" autoload :CLI, "middleman/cli"
autoload :Templates, "middleman/templates" autoload :Templates, "middleman/templates"
@ -80,6 +79,11 @@ module Middleman
end end
module CoreExtensions module CoreExtensions
# Guard Proxy
autoload :FileWatcher, "middleman/core_extensions/file_watcher"
autoload :Sitemap, "middleman/core_extensions/sitemap"
# Add Builder callbacks # Add Builder callbacks
autoload :Builder, "middleman/core_extensions/builder" autoload :Builder, "middleman/core_extensions/builder"
@ -187,13 +191,14 @@ module Middleman
:AccessLog => [] :AccessLog => []
} }
app = ::Middleman.server app_class = options[:app] ||= ::Middleman.server
app.set :environment, options[:environment].to_sym app_class.set :environment, options[:environment].to_sym
opts[:app] = app.new opts[:app] = app_class.new
opts[:server] = 'thin' opts[:server] = 'thin'
$stderr.puts "== The Middleman is standing watch on port #{opts[:Port]}" server = ::Rack::Server.new(opts)
::Rack::Server.new(opts).start server.start
server
end end
end end

View file

@ -38,6 +38,12 @@ module Middleman::Base
app.set :views, "source" app.set :views, "source"
# Add Builder Callbacks
app.register Middleman::CoreExtensions::FileWatcher
# Sitemap
app.register Middleman::CoreExtensions::Sitemap
# Add Builder Callbacks # Add Builder Callbacks
app.register Middleman::CoreExtensions::Builder app.register Middleman::CoreExtensions::Builder
@ -92,7 +98,8 @@ module Middleman::Base
# See if Tilt cannot handle this file # See if Tilt cannot handle this file
app.before_processing(:base) do |result| app.before_processing(:base) do |result|
request_path = request.path_info.gsub("%20", " ") request_path = request.path_info.gsub("%20", " ")
should_be_ignored = !(request["is_proxy"]) && settings.excluded_paths.include?("/#{request_path}")
should_be_ignored = !(request["is_proxy"]) && settings.sitemap.ignored_path?("/#{request_path}")
if result && !should_be_ignored if result && !should_be_ignored
extensionless_path, template_engine = result extensionless_path, template_engine = result

View file

@ -12,9 +12,6 @@ module Middleman
config = args.last.is_a?(Hash) ? args.pop : {} config = args.last.is_a?(Hash) ? args.pop : {}
destination = args.first || source destination = args.first || source
# source = File.expand_path(find_in_source_paths(source.to_s))
# context = instance_eval('binding')
request_path = destination.sub(/^#{SHARED_SERVER.build_dir}/, "") request_path = destination.sub(/^#{SHARED_SERVER.build_dir}/, "")
begin begin
@ -23,62 +20,12 @@ module Middleman
request_path.gsub!(/\s/, "%20") request_path.gsub!(/\s/, "%20")
response = Middleman::Builder.shared_rack.get(request_path) response = Middleman::Builder.shared_rack.get(request_path)
dequeue_file_from destination if cleaning?
create_file destination, nil, config do create_file destination, nil, config do
response.body response.body
end if response.status == 200 end if response.status == 200
rescue rescue
end end
end end
def clean!(destination)
return unless cleaning?
queue_current_paths_from destination
add_clean_up_callback
end
def cleaning?
options.has_key?("clean") && options["clean"]
end
def add_clean_up_callback
clean_up_callback = lambda do
files = @cleaning_queue.select { |q| File.file? q }
directories = @cleaning_queue.select { |q| File.directory? q }
files.each { |f| remove_file f, :force => true }
directories = directories.sort_by {|d| d.length }.reverse!
directories.each do |d|
remove_file d, :force => true if directory_empty? d
end
end
self.class.after_run :clean_up_callback do
clean_up_callback.call
end
end
def directory_empty?(directory)
Dir["#{directory}/*"].empty?
end
def queue_current_paths_from(destination)
@cleaning_queue = []
Find.find(destination) do |path|
next if path.match(/\/\./)
unless path == destination
@cleaning_queue << path.sub(destination, destination[/([^\/]+?)$/])
end
end
end
def dequeue_file_from(destination)
@cleaning_queue.delete_if {|q| q == destination }
end
end end
class Builder < Thor::Group class Builder < Thor::Group
@ -114,15 +61,11 @@ module Middleman
def build_all_files def build_all_files
self.class.shared_rack self.class.shared_rack
if options.has_key?("glob") opts = { }
action GlobAction.new(self, SHARED_SERVER.views, SHARED_SERVER.build_dir, { :force => true, :glob => options["glob"] }) opts[:glob] = options["glob"] if options.has_key?("glob")
else opts[:clean] = options["clean"] if options.has_key?("clean")
action DirectoryAction.new(self, SHARED_SERVER.views, SHARED_SERVER.build_dir, { :force => true })
SHARED_SERVER.proxied_paths.each do |url, proxy| action GlobAction.new(self, SHARED_SERVER, opts)
tilt_template(url.gsub(/^\//, "#{SHARED_SERVER.build_dir}/"), { :force => true })
end
end
end end
@@hooks = {} @@hooks = {}
@ -143,18 +86,23 @@ module Middleman
end end
end end
class BaseAction < ::Thor::Actions::EmptyDirectory class GlobAction < ::Thor::Actions::EmptyDirectory
attr_reader :source attr_reader :source
def initialize(base, source, destination=nil, config={}, &block) def initialize(base, app, config={}, &block)
@app = app
source = @app.views
@destination = @app.build_dir
@source = File.expand_path(base.find_in_source_paths(source.to_s)) @source = File.expand_path(base.find_in_source_paths(source.to_s))
@block = block
super(base, destination, { :recursive => true }.merge(config)) super(base, destination, config)
end end
def invoke! def invoke!
base.clean! destination queue_current_paths if cleaning?
execute! execute!
clean! if cleaning?
end end
def revoke! def revoke!
@ -162,94 +110,75 @@ module Middleman
end end
protected protected
def handle_path(file_source)
# Skip partials prefixed with an underscore while still handling files prefixed with 2 consecutive underscores
return unless file_source.gsub(SHARED_SERVER.root, '').split('/').select { |p| p[/^_[^_]/] }.empty?
file_extension = File.extname(file_source) def clean!
file_destination = File.join(given_destination, file_source.gsub(source, '.')) files = @cleaning_queue.select { |q| File.file? q }
file_destination.gsub!('/./', '/') directories = @cleaning_queue.select { |q| File.directory? q }
handled_by_tilt = ::Tilt.mappings.has_key?(file_extension.gsub(/^\./, "")) files.each do |f|
if handled_by_tilt base.remove_file f, :force => true
file_destination.gsub!(file_extension, "")
end end
destination = base.tilt_template(file_source, file_destination, config, &@block) directories = directories.sort_by {|d| d.length }.reverse!
directories.each do |d|
base.remove_file d, :force => true if directory_empty? d
end end
end end
class GlobAction < BaseAction def cleaning?
@config.has_key?(:clean) && @config[:clean]
end
def directory_empty?(directory)
Dir["#{directory}/*"].empty?
end
def queue_current_paths
@cleaning_queue = []
Find.find(@destination) do |path|
next if path.match(/\/\./)
unless path == destination
@cleaning_queue << path.sub(@destination, destination[/([^\/]+?)$/])
end
end
end
protected
def execute! def execute!
Dir[File.join(source, @config[:glob])].each do |path| paths = @app.sitemap.all_paths.sort do |a, b|
file_name = path.gsub(SHARED_SERVER.views + "/", "") a_dir = a.split("/").first
if file_name == "layouts" b_dir = b.split("/").first
false
elsif file_name.include?("layout.") && file_name.split(".").length == 2
false
else
next if File.directory?(path)
handle_path(path) if a_dir == @app.images_dir
true
end
end
end
end
class DirectoryAction < BaseAction
def invoke!
base.empty_directory given_destination, config
super
end
protected
def handle_directory(lookup, &block)
lookup = File.join(lookup, '*')
results = Dir[lookup].sort do |a, b|
simple_a = a.gsub(SHARED_SERVER.root + "/", '').gsub(SHARED_SERVER.views + "/", '')
simple_b = b.gsub(SHARED_SERVER.root + "/", '').gsub(SHARED_SERVER.views + "/", '')
a_dir = simple_a.split("/").first
b_dir = simple_b.split("/").first
if a_dir == SHARED_SERVER.images_dir
-1 -1
elsif b_dir == SHARED_SERVER.images_dir elsif b_dir == @app.images_dir
1 1
else else
0 0
end end
end end
results = results.select(&block) if block_given? paths.each do |path|
file_source = path
file_destination = File.join(given_destination, file_source.gsub(source, '.'))
file_destination.gsub!('/./', '/')
results.each do |file_source| if @app.sitemap.generic_path?(file_source)
if File.directory?(file_source) # no-op
handle_directory(file_source) elsif @app.sitemap.proxied_path?(file_source)
file_source = @app.sitemap.path_target(file_source)
elsif @app.sitemap.ignored_path?(file_source)
next next
end end
handle_path(file_source) @cleaning_queue.delete(file_destination) if cleaning?
end
if @config[:glob]
next unless File.fnmatch(@config[:glob], file_source)
end end
def execute! base.tilt_template(file_source, file_destination, { :force => true })
handle_directory(source) do |path|
file_name = path.gsub(SHARED_SERVER.views + "/", "")
if file_name == "layouts"
false
elsif file_name.include?("layout.") && file_name.split(".").length == 2
false
else
true
end end
end end
end end
end
end end

View file

@ -59,7 +59,7 @@ module Middleman::CoreExtensions::Features
feature = Middleman::Features.const_get(feature) feature = Middleman::Features.const_get(feature)
end end
$stderr.puts "== Activating: #{feature}" if logging? puts "== Activating: #{feature}" if logging?
register feature register feature
end end
@ -75,12 +75,10 @@ module Middleman::CoreExtensions::Features
# Load features before starting server # Load features before starting server
def new def new
set :sitemap, ::Middleman::Sitemap.new(self)
# Check for and evaluate local configuration # Check for and evaluate local configuration
local_config = File.join(self.root, "config.rb") local_config = File.join(self.root, "config.rb")
if File.exists? local_config if File.exists? local_config
$stderr.puts "== Reading: Local config" if logging? puts "== Reading: Local config" if logging?
class_eval File.read(local_config) class_eval File.read(local_config)
set :app_file, File.expand_path(local_config) set :app_file, File.expand_path(local_config)
end end
@ -94,7 +92,7 @@ module Middleman::CoreExtensions::Features
if logging? if logging?
extensions.each do |ext| extensions.each do |ext|
$stderr.puts "== Extension: #{ext}" puts "== Extension: #{ext}"
end end
end end

View file

@ -0,0 +1,30 @@
module Middleman::CoreExtensions::FileWatcher
class << self
def registered(app)
app.extend ClassMethods
end
alias :included :registered
end
module ClassMethods
def file_did_change(path)
@run_after_file_change ||= []
@run_after_file_change.each { |block| block.call(path) }
end
def on_file_change(&block)
@run_after_file_change ||= []
@run_after_file_change << block
end
def file_did_delete(path)
@run_after_file_delete ||= []
@run_after_file_delete.each { |block| block.call(path) }
end
def on_file_delete(&block)
@run_after_file_delete ||= []
@run_after_file_delete << block
end
end
end

View file

@ -48,12 +48,7 @@ module Middleman::CoreExtensions::Routing
# Keep a path from building # Keep a path from building
def ignore(path) def ignore(path)
# New sitemap based ignore
settings.sitemap.ignore_path(path) settings.sitemap.ignore_path(path)
settings.excluded_paths << paths_for_url(path)
settings.excluded_paths.flatten!
settings.excluded_paths.uniq!
end end
# The page method allows the layout to be set on a specific path # The page method allows the layout to be set on a specific path
@ -64,10 +59,8 @@ module Middleman::CoreExtensions::Routing
options[:layout] = settings.layout if options[:layout].nil? options[:layout] = settings.layout if options[:layout].nil?
if options.has_key?(:proxy) if options.has_key?(:proxy)
# New sitemap based proxy
settings.sitemap.set_path(url, options[:proxy]) settings.sitemap.set_path(url, options[:proxy])
settings.proxied_paths[url] = options[:proxy]
if options.has_key?(:ignore) && options[:ignore] if options.has_key?(:ignore) && options[:ignore]
settings.ignore(options[:proxy]) settings.ignore(options[:proxy])
end end
@ -79,17 +72,11 @@ module Middleman::CoreExtensions::Routing
paths_for_url(url).each do |p| paths_for_url(url).each do |p|
get(p) do get(p) do
# New sitemap based rerouting
if settings.sitemap.path_is_proxy?(url) if settings.sitemap.path_is_proxy?(url)
request["is_proxy"] = true request["is_proxy"] = true
request.path_info = settings.sitemap.path_target(url) request.path_info = settings.sitemap.path_target(url)
end end
if settings.proxied_paths.has_key?(url)
request["is_proxy"] = true
request.path_info = settings.proxied_paths[url]
end
instance_eval(&block) if has_block instance_eval(&block) if has_block
process_request(options) process_request(options)
end end

View file

@ -1,88 +1,116 @@
require 'find' require 'find'
module Middleman module Middleman::CoreExtensions::Sitemap
class Sitemap class << self
def self.singleton def registered(app)
@@singleton || nil app.set :sitemap, SitemapStore.new(app)
end
alias :included :registered
end end
class SitemapStore
def initialize(app) def initialize(app)
@app = app @app = app
@map = {} @map = {}
@ignored_paths = nil @ignored_paths = false
@generic_paths = nil @generic_paths = false
@proxied_paths = nil @proxied_paths = false
@source = File.expand_path(@app.views, @app.root) @source = File.expand_path(@app.views, @app.root)
build_static_map build_static_map
each do |request, destination| @app.on_file_change do |file|
$stderr.puts request touch_file(file)
end end
@@singleton = self @app.on_file_delete do |file|
remove_file(file)
end
end end
# Check to see if we know about a specific path # Check to see if we know about a specific path
def path_exists?(path) def path_exists?(path)
path = path.sub(/^\//, "")
@map.has_key?(path) @map.has_key?(path)
end end
def path_is_proxy?(path) def path_is_proxy?(path)
path = path.sub(/^\//, "")
return false if !path_exists?(path) return false if !path_exists?(path)
@map[path].is_a?(String) @map[path].is_a?(String)
end end
def path_target(path) def path_target(path)
path = path.sub(/^\//, "")
@map[path] @map[path]
end end
def set_path(path, target=true) def set_path(path, target=true)
path = path.sub(/^\//, "")
target = target.sub(/^\//, "") if target.is_a?(String)
@map[path] = target @map[path] = target
@ignored_paths = nil if target.nil? @ignored_paths = false if target === false
@generic_paths = nil if target === true @generic_paths = false if target === true
@proxied_paths = nil if target.is_a?(String) @proxied_paths = false if target.is_a?(String)
end end
def ignore_path(path) def ignore_path(path)
set_path(path, nil) set_path(path, false)
end end
def each(&block) def each(&block)
@map.each do |k, v| @map.each do |k, v|
next if v.nil?
yield(k, v) yield(k, v)
end end
end end
def all_paths
@map.keys
end
def ignored_path?(path)
path = path.sub(/^\//, "")
ignored_paths.include?(path)
end
def ignored_paths def ignored_paths
@ignored_paths ||= begin @ignored_paths ||= begin
ignored = [] ignored = []
each do |k, v| each do |k, v|
ignored << k unless v.nil? ignored << k if v === false
end end
ignored ignored
end end
end end
def generic_path?(path)
path = path.sub(/^\//, "")
generic_paths.include?(path)
end
def generic_paths def generic_paths
@generic_paths ||= begin @generic_paths ||= begin
generic = [] generic = []
each do |k, v| each do |k, v|
generic << k unless v === true generic << k if v === true
end end
generic generic
end end
end end
def proxied_path?(path)
path = path.sub(/^\//, "")
proxied_paths.include?(path)
end
def proxied_paths def proxied_paths
@proxied_paths ||= begin @proxied_paths ||= begin
proxied = [] proxied = []
each do |k, v| each do |k, v|
proxied << k unless target.is_a?(String) proxied << k if v.is_a?(String)
end end
proxied proxied
end end
@ -101,16 +129,12 @@ module Middleman
end end
def remove_path(path) def remove_path(path)
if @map.has_key?(path) path = path.sub(/^\//, "")
@map.delete(path) @map.delete(path) if path_exists?(path)
end
end end
protected protected
def build_static_map def build_static_map
# found_template = resolve_template(request_path, :raise_exceptions => false)
Find.find(@source) do |file| Find.find(@source) do |file|
add_file(file) add_file(file)
end end
@ -153,33 +177,3 @@ module Middleman
end end
end end
end end
module Guard
class MiddlemanSitemap < Guard
def initialize(watchers = [], options = {})
super
@options = options
end
def run_on_change(files)
files.each do |file|
::Middleman::Sitemap.singleton.touch_file(file)
end
end
def run_on_deletion(files)
files.each do |file|
::Middleman::Sitemap.singleton.remove_file(file)
end
end
end
end
# Add Sitemap guard
Middleman::Guard.add_guard do
%Q{
guard 'middlemansitemap' do
watch(%r{^source/(.*)})
end
}
end

View file

@ -9,8 +9,7 @@ end
module Middleman module Middleman
module Guard module Guard
def self.add_guard(&block) def self.add_guard(&block)
@additional_guards ||= [] # Deprecation Warning
@additional_guards << block
end end
def self.start(options={}, livereload={}) def self.start(options={}, livereload={})
@ -20,24 +19,18 @@ module Middleman
end end
guardfile_contents = %Q{ guardfile_contents = %Q{
guard 'middlemanconfig'#{options_hash} do guard 'middleman'#{options_hash} do
watch("config.rb") watch(%r{(.*)})
watch(%r{^lib/^[^\.](.*)\.rb$})
end end
} }
(@additional_guards || []).each do |block|
result = block.call(options, livereload)
guardfile_contents << result unless result.nil?
end
::Guard.start({ :guardfile_contents => guardfile_contents }) ::Guard.start({ :guardfile_contents => guardfile_contents })
end end
end end
end end
module Guard module Guard
class MiddlemanConfig < Guard class Middleman < Guard
def initialize(watchers = [], options = {}) def initialize(watchers = [], options = {})
super super
@options = options @options = options
@ -48,14 +41,46 @@ module Guard
end end
def run_on_change(paths) def run_on_change(paths)
needs_to_restart = false
paths.each do |path|
if path.match(%{^config\.rb}) || path.match(%r{^lib/^[^\.](.*)\.rb$})
needs_to_restart = true
break
end
end
if needs_to_restart
server_restart
elsif !@app.nil?
paths.each do |path|
@app.file_did_change(path)
end
end
end
def run_on_deletion(paths)
if !@app.nil?
paths.each do |path|
@app.file_did_delete(path)
end
end
end
private
def server_restart
server_stop server_stop
server_start server_start
end end
private
def server_start def server_start
@app = ::Middleman.server
puts "== The Middleman is standing watch on port #{@options[:Port]}"
@server_job = fork do @server_job = fork do
::Middleman.start_server(@options) opts = @options.dup
opts[:app] = @app
::Middleman.start_server(opts)
end end
end end
@ -64,9 +89,7 @@ module Guard
Process.kill("KILL", @server_job) Process.kill("KILL", @server_job)
Process.wait @server_job Process.wait @server_job
@server_job = nil @server_job = nil
# @server_options[:app] = nil @app = nil
end end
end end
end end
require "middleman/sitemap"