middleman 3.0.0.alpha.5 → 3.0.0.alpha.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +3 -2
- data/README.md +7 -7
- data/bin/middleman +3 -2
- data/features/builder.feature +4 -0
- data/features/cli.feature +10 -11
- data/features/nested_layouts.feature +24 -0
- data/features/sitemap_traversal.features +56 -0
- data/fixtures/empty-app/not-config.rb +0 -0
- data/fixtures/nested-layout-app/config.rb +1 -0
- data/fixtures/nested-layout-app/source/data-one.html.erb +5 -0
- data/fixtures/nested-layout-app/source/data-two.html.erb +5 -0
- data/fixtures/nested-layout-app/source/index.html.erb +1 -0
- data/fixtures/nested-layout-app/source/layouts/inner.erb +4 -0
- data/fixtures/nested-layout-app/source/layouts/master.erb +3 -0
- data/fixtures/nested-layout-app/source/layouts/outer.erb +4 -0
- data/fixtures/traversal-app/config.rb +2 -0
- data/fixtures/traversal-app/source/index.html.erb +0 -0
- data/fixtures/traversal-app/source/layout.erb +13 -0
- data/fixtures/traversal-app/source/proxied.html.erb +0 -0
- data/fixtures/traversal-app/source/root.html.erb +0 -0
- data/fixtures/traversal-app/source/sub/index.html.erb +0 -0
- data/fixtures/traversal-app/source/sub/sibling.html.erb +0 -0
- data/fixtures/traversal-app/source/sub/sibling2.html.erb +0 -0
- data/fixtures/traversal-app/source/sub/sub2/index.html.erb +0 -0
- data/fixtures/traversal-app/source/sub/sub3/deep.html.erb +0 -0
- data/lib/middleman.rb +0 -3
- data/lib/middleman/base.rb +3 -28
- data/lib/middleman/cli/server.rb +0 -1
- data/lib/middleman/core_extensions/builder.rb +1 -7
- data/lib/middleman/core_extensions/default_helpers.rb +27 -1
- data/lib/middleman/core_extensions/extensions.rb +20 -4
- data/lib/middleman/core_extensions/file_watcher.rb +25 -8
- data/lib/middleman/core_extensions/front_matter.rb +5 -12
- data/lib/middleman/core_extensions/rendering.rb +10 -0
- data/lib/middleman/core_extensions/sitemap.rb +4 -0
- data/lib/middleman/guard.rb +11 -11
- data/lib/middleman/sitemap/page.rb +55 -0
- data/lib/middleman/sitemap/template.rb +9 -3
- data/lib/middleman/step_definitions.rb +0 -1
- data/lib/middleman/templates/default.rb +7 -2
- data/lib/middleman/templates/default/source/images/background.png +0 -0
- data/lib/middleman/templates/default/source/images/middleman.png +0 -0
- data/lib/middleman/templates/default/source/index.html.erb +9 -4
- data/lib/middleman/templates/default/source/javascripts/all.js +1 -0
- data/lib/middleman/templates/default/source/layouts/layout.erb +19 -0
- data/lib/middleman/templates/default/source/stylesheets/_animate.scss +23 -0
- data/lib/middleman/templates/default/source/stylesheets/_normalize.scss +431 -0
- data/lib/middleman/templates/default/source/stylesheets/all.css.scss +40 -0
- data/lib/middleman/templates/shared/config.tt +4 -16
- data/lib/middleman/version.rb +1 -1
- data/middleman-x86-mingw32.gemspec +1 -1
- data/middleman.gemspec +1 -1
- metadata +54 -13
- data/features/generator.feature +0 -8
- data/lib/middleman/extensions/sitemap_tree.rb +0 -38
- data/lib/middleman/step_definitions/generator_steps.rb +0 -26
- data/lib/middleman/templates/default/source/layout.erb +0 -19
- data/lib/middleman/templates/default/source/stylesheets/site.css.scss +0 -32
@@ -31,9 +31,12 @@
|
|
31
31
|
# Using for version parsing
|
32
32
|
require "rubygems"
|
33
33
|
|
34
|
+
# Namespace extensions module
|
34
35
|
module Middleman::CoreExtensions::Extensions
|
35
36
|
|
37
|
+
# Register extension
|
36
38
|
class << self
|
39
|
+
# @private
|
37
40
|
def included(app)
|
38
41
|
# app.set :default_extensions, []
|
39
42
|
app.define_hook :after_configuration
|
@@ -43,18 +46,31 @@ module Middleman::CoreExtensions::Extensions
|
|
43
46
|
|
44
47
|
app.extend ClassMethods
|
45
48
|
app.send :include, InstanceMethods
|
49
|
+
app.delegate :configure, :to => :"self.class"
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
53
|
+
# Class methods
|
49
54
|
module ClassMethods
|
55
|
+
# Add a callback to run in a specific environment
|
56
|
+
#
|
57
|
+
# @param [String, Symbol] env The environment to run in
|
58
|
+
# @return [void]
|
50
59
|
def configure(env, &block)
|
51
60
|
send("#{env}_config", &block)
|
52
61
|
end
|
53
62
|
|
63
|
+
# Alias `extensions` to access registered extensions
|
64
|
+
#
|
65
|
+
# @return [Array<Module]
|
54
66
|
def extensions
|
55
67
|
@extensions ||= []
|
56
68
|
end
|
57
69
|
|
70
|
+
# Register a new extension
|
71
|
+
#
|
72
|
+
# @param [Array<Module>] new_extensions Extension modules to register
|
73
|
+
# @return [Array<Module]
|
58
74
|
def register(*new_extensions)
|
59
75
|
@extensions ||= []
|
60
76
|
@extensions += new_extensions
|
@@ -65,12 +81,16 @@ module Middleman::CoreExtensions::Extensions
|
|
65
81
|
end
|
66
82
|
end
|
67
83
|
|
84
|
+
# Instance methods
|
68
85
|
module InstanceMethods
|
69
86
|
# This method is available in the project's `config.rb`.
|
70
87
|
# It takes a underscore-separated symbol, finds the appropriate
|
71
88
|
# feature module and includes it.
|
72
89
|
#
|
73
90
|
# activate :lorem
|
91
|
+
#
|
92
|
+
# @param [Symbol, Module] feature Which extension to activate
|
93
|
+
# @return [void]
|
74
94
|
def activate(feature)
|
75
95
|
ext = ::Middleman::Extensions.load(feature.to_sym)
|
76
96
|
|
@@ -83,10 +103,6 @@ module Middleman::CoreExtensions::Extensions
|
|
83
103
|
self.class.register(ext)
|
84
104
|
end
|
85
105
|
end
|
86
|
-
|
87
|
-
def configure(env, &block)
|
88
|
-
self.class.configure(env, &block)
|
89
|
-
end
|
90
106
|
|
91
107
|
# Load features before starting server
|
92
108
|
def initialize
|
@@ -1,11 +1,17 @@
|
|
1
1
|
require "find"
|
2
2
|
|
3
|
+
# API for watching file change events
|
3
4
|
module Middleman::CoreExtensions::FileWatcher
|
5
|
+
# Setup extension
|
4
6
|
class << self
|
7
|
+
# @private
|
5
8
|
def registered(app)
|
6
9
|
app.extend ClassMethods
|
7
10
|
app.send :include, InstanceMethods
|
8
11
|
|
12
|
+
app.delegate :file_changed, :file_deleted, :to => :"self.class"
|
13
|
+
|
14
|
+
# Before parsing config, load the data/ directory
|
9
15
|
app.before_configuration do
|
10
16
|
data_path = File.join(root, data_dir)
|
11
17
|
Find.find(data_path) do |path|
|
@@ -14,6 +20,7 @@ module Middleman::CoreExtensions::FileWatcher
|
|
14
20
|
end if File.exists?(data_path)
|
15
21
|
end
|
16
22
|
|
23
|
+
# After config, load everything else
|
17
24
|
app.ready do
|
18
25
|
Find.find(root) do |path|
|
19
26
|
next if File.directory?(path)
|
@@ -24,13 +31,22 @@ module Middleman::CoreExtensions::FileWatcher
|
|
24
31
|
alias :included :registered
|
25
32
|
end
|
26
33
|
|
34
|
+
# Class methods
|
27
35
|
module ClassMethods
|
36
|
+
# Add callback to be run on file change
|
37
|
+
#
|
38
|
+
# @param [nil,Regexp] matcher A Regexp to match the change path against
|
39
|
+
# @return [Array<Proc>]
|
28
40
|
def file_changed(matcher=nil, &block)
|
29
41
|
@_file_changed ||= []
|
30
42
|
@_file_changed << [block, matcher] if block_given?
|
31
43
|
@_file_changed
|
32
44
|
end
|
33
45
|
|
46
|
+
# Add callback to be run on file deletion
|
47
|
+
#
|
48
|
+
# @param [nil,Regexp] matcher A Regexp to match the deleted path against
|
49
|
+
# @return [Array<Proc>]
|
34
50
|
def file_deleted(matcher=nil, &block)
|
35
51
|
@_file_deleted ||= []
|
36
52
|
@_file_deleted << [block, matcher] if block_given?
|
@@ -38,11 +54,12 @@ module Middleman::CoreExtensions::FileWatcher
|
|
38
54
|
end
|
39
55
|
end
|
40
56
|
|
57
|
+
# Instance methods
|
41
58
|
module InstanceMethods
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
59
|
+
# Notify callbacks that a file changed
|
60
|
+
#
|
61
|
+
# @param [String] path The file that changed
|
62
|
+
# @return [void]
|
46
63
|
def file_did_change(path)
|
47
64
|
file_changed.each do |callback, matcher|
|
48
65
|
next if path.match(%r{^#{build_dir}/})
|
@@ -50,11 +67,11 @@ module Middleman::CoreExtensions::FileWatcher
|
|
50
67
|
instance_exec(path, &callback)
|
51
68
|
end
|
52
69
|
end
|
53
|
-
|
54
|
-
def file_deleted(*args)
|
55
|
-
self.class.file_deleted(*args)
|
56
|
-
end
|
57
70
|
|
71
|
+
# Notify callbacks that a file was deleted
|
72
|
+
#
|
73
|
+
# @param [String] path The file that was deleted
|
74
|
+
# @return [void]
|
58
75
|
def file_did_delete(path)
|
59
76
|
file_deleted.each do |callback, matcher|
|
60
77
|
next if path.match(%r{^#{build_dir}/})
|
@@ -7,6 +7,7 @@ module Middleman::CoreExtensions::FrontMatter
|
|
7
7
|
app.set :frontmatter_extensions, %w(.htm .html .php)
|
8
8
|
app.extend ClassMethods
|
9
9
|
app.send :include, InstanceMethods
|
10
|
+
app.delegate :frontmatter_changed, :to => :"self.class"
|
10
11
|
end
|
11
12
|
alias :included :registered
|
12
13
|
end
|
@@ -37,28 +38,20 @@ module Middleman::CoreExtensions::FrontMatter
|
|
37
38
|
provides_metadata matcher do |path|
|
38
39
|
relative_path = path.sub(source_dir, "")
|
39
40
|
|
40
|
-
|
41
|
+
fmdata = if frontmatter.has_data?(relative_path)
|
41
42
|
frontmatter.data(relative_path)[0]
|
42
43
|
else
|
43
44
|
{}
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
-
data_content("page", data)
|
48
|
-
|
47
|
+
data = {}
|
49
48
|
%w(layout layout_engine).each do |opt|
|
50
|
-
if
|
51
|
-
data[opt.to_sym] = data.delete(opt)
|
52
|
-
end
|
49
|
+
data[opt.to_sym] = fmdata[opt] if fmdata.has_key?(opt)
|
53
50
|
end
|
54
51
|
|
55
|
-
{ :options => data }
|
52
|
+
{ :options => data, :page => fmdata }
|
56
53
|
end
|
57
54
|
end
|
58
|
-
|
59
|
-
def frontmatter_changed(*args, &block)
|
60
|
-
self.class.frontmatter_changed(*args, &block)
|
61
|
-
end
|
62
55
|
|
63
56
|
def frontmatter_did_change(path)
|
64
57
|
frontmatter_changed.each do |callback, matcher|
|
@@ -44,6 +44,8 @@ module Middleman::CoreExtensions::Rendering
|
|
44
44
|
# the template don't persist for other templates.
|
45
45
|
context = self.dup
|
46
46
|
|
47
|
+
@current_locs = locs, @current_opts = opts
|
48
|
+
|
47
49
|
while ::Tilt[path]
|
48
50
|
content = render_individual_file(path, locs, opts, context)
|
49
51
|
path = File.basename(path, File.extname(path))
|
@@ -60,6 +62,8 @@ module Middleman::CoreExtensions::Rendering
|
|
60
62
|
ensure
|
61
63
|
@current_engine = engine_was
|
62
64
|
@content_blocks = nil
|
65
|
+
@current_locs = nil
|
66
|
+
@current_opts = nil
|
63
67
|
end
|
64
68
|
|
65
69
|
# Sinatra/Padrino render method signature.
|
@@ -198,6 +202,12 @@ module Middleman::CoreExtensions::Rendering
|
|
198
202
|
|
199
203
|
layout_path
|
200
204
|
end
|
205
|
+
|
206
|
+
def wrap_layout(layout_name, &block)
|
207
|
+
content = capture(&block) if block_given?
|
208
|
+
layout_path = locate_layout(layout_name, current_engine)
|
209
|
+
concat render_individual_file(layout_path, @current_locs || {}, @current_opts || {}, self) { content }
|
210
|
+
end
|
201
211
|
|
202
212
|
def current_engine
|
203
213
|
@current_engine ||= nil
|
data/lib/middleman/guard.rb
CHANGED
@@ -41,12 +41,6 @@ module Guard
|
|
41
41
|
def initialize(watchers = [], options = {})
|
42
42
|
super
|
43
43
|
@options = options
|
44
|
-
|
45
|
-
# Trap the interupt signal and shut down Guard (and thus the server) smoothly
|
46
|
-
trap(kill_command) do
|
47
|
-
::Guard.stop
|
48
|
-
exit!(0)
|
49
|
-
end
|
50
44
|
end
|
51
45
|
|
52
46
|
# Start Middleman in a fork
|
@@ -81,7 +75,7 @@ module Guard
|
|
81
75
|
puts "== The Middleman is shutting down"
|
82
76
|
if ::Middleman::JRUBY
|
83
77
|
else
|
84
|
-
Process.kill(
|
78
|
+
Process.kill(::Middleman::WINDOWS ? :KILL : :TERM, @server_job)
|
85
79
|
Process.wait @server_job
|
86
80
|
@server_job = nil
|
87
81
|
end
|
@@ -113,6 +107,10 @@ module Guard
|
|
113
107
|
paths.each { |path| tell_server(:delete => path) }
|
114
108
|
end
|
115
109
|
|
110
|
+
def self.kill_command
|
111
|
+
::Middleman::WINDOWS ? 1 : :INT
|
112
|
+
end
|
113
|
+
|
116
114
|
private
|
117
115
|
# Whether the passed files are config.rb or lib/*.rb
|
118
116
|
# @param [Array<String>] paths Array of paths to check
|
@@ -129,9 +127,11 @@ module Guard
|
|
129
127
|
uri = URI.parse("http://#{@options[:host]}:#{@options[:port]}/__middleman__")
|
130
128
|
Net::HTTP.post_form(uri, {}.merge(params))
|
131
129
|
end
|
132
|
-
|
133
|
-
def kill_command
|
134
|
-
::Middleman::WINDOWS ? 1 : :INT
|
135
|
-
end
|
136
130
|
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Trap the interupt signal and shut down Guard (and thus the server) smoothly
|
134
|
+
trap(::Guard::Middleman.kill_command) do
|
135
|
+
::Guard.stop
|
136
|
+
exit!(0)
|
137
137
|
end
|
@@ -99,6 +99,61 @@ module Middleman::Sitemap
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
|
+
def directory_index?
|
103
|
+
path.include?(app.index_file) || path =~ /\/$/
|
104
|
+
end
|
105
|
+
|
106
|
+
def parent
|
107
|
+
parts = path.split("/")
|
108
|
+
if path.include?(app.index_file)
|
109
|
+
parts.pop
|
110
|
+
else
|
111
|
+
end
|
112
|
+
|
113
|
+
return nil if parts.length < 1
|
114
|
+
|
115
|
+
parts.pop
|
116
|
+
parts.push(app.index_file)
|
117
|
+
|
118
|
+
parent_path = "/" + parts.join("/")
|
119
|
+
|
120
|
+
if store.exists?(parent_path)
|
121
|
+
store.page(parent_path)
|
122
|
+
else
|
123
|
+
nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def children
|
128
|
+
return [] unless directory_index?
|
129
|
+
|
130
|
+
base_path = path.sub("#{app.index_file}", "")
|
131
|
+
prefix = /^#{base_path.sub("/", "\\/")}/
|
132
|
+
|
133
|
+
store.all_paths.select do |sub_path|
|
134
|
+
sub_path =~ prefix
|
135
|
+
end.select do |sub_path|
|
136
|
+
path != sub_path
|
137
|
+
end.select do |sub_path|
|
138
|
+
relative_path = sub_path.sub(prefix, "")
|
139
|
+
parts = relative_path.split("/")
|
140
|
+
if parts.length == 1
|
141
|
+
true
|
142
|
+
elsif parts.length == 2
|
143
|
+
parts.last == app.index_file
|
144
|
+
else
|
145
|
+
false
|
146
|
+
end
|
147
|
+
end.map do |p|
|
148
|
+
store.page(p)
|
149
|
+
end.reject { |p| p.ignored? }
|
150
|
+
end
|
151
|
+
|
152
|
+
def siblings
|
153
|
+
return [] unless parent
|
154
|
+
parent.children.reject { |p| p == self }
|
155
|
+
end
|
156
|
+
|
102
157
|
protected
|
103
158
|
def app
|
104
159
|
@store.app
|
@@ -36,7 +36,7 @@ module Middleman::Sitemap
|
|
36
36
|
|
37
37
|
def metadata
|
38
38
|
metadata = app.cache.fetch(:metadata, source_file) do
|
39
|
-
data = { :options => {}, :locals => {} }
|
39
|
+
data = { :options => {}, :locals => {}, :page => {} }
|
40
40
|
|
41
41
|
app.provides_metadata.each do |callback, matcher|
|
42
42
|
next if !matcher.nil? && !source_file.match(matcher)
|
@@ -57,8 +57,14 @@ module Middleman::Sitemap
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def render(opts={}, locs={}, &block)
|
60
|
-
|
61
|
-
|
60
|
+
md = metadata.dup
|
61
|
+
opts = options.deep_merge(md[:options]).deep_merge(opts)
|
62
|
+
locs = locals.deep_merge(md[:locals]).deep_merge(locs)
|
63
|
+
|
64
|
+
# Forward remaining data to helpers
|
65
|
+
if md.has_key?(:page)
|
66
|
+
app.data_content("page", md[:page])
|
67
|
+
end
|
62
68
|
|
63
69
|
blocks.compact.each do |block|
|
64
70
|
app.instance_eval(&block)
|
@@ -5,7 +5,6 @@ ENV['PATH'] = "#{MIDDLEMAN_BIN_PATH}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
|
5
5
|
require "aruba/cucumber"
|
6
6
|
require "middleman/step_definitions/middleman_steps"
|
7
7
|
require "middleman/step_definitions/builder_steps"
|
8
|
-
require "middleman/step_definitions/generator_steps"
|
9
8
|
require "middleman/step_definitions/server_steps"
|
10
9
|
|
11
10
|
Before do
|
@@ -12,11 +12,16 @@ class Middleman::Templates::Default < Middleman::Templates::Base
|
|
12
12
|
def build_scaffold!
|
13
13
|
template "shared/config.tt", File.join(location, "config.rb")
|
14
14
|
copy_file "default/source/index.html.erb", File.join(location, "source/index.html.erb")
|
15
|
-
copy_file "default/source/layout.erb", File.join(location, "source/layout.erb")
|
15
|
+
copy_file "default/source/layouts/layout.erb", File.join(location, "source/layouts/layout.erb")
|
16
16
|
empty_directory File.join(location, "source", options[:css_dir])
|
17
|
-
copy_file "default/source/stylesheets/
|
17
|
+
copy_file "default/source/stylesheets/all.css.scss", File.join(location, "source", options[:css_dir], "all.css.scss")
|
18
|
+
copy_file "default/source/stylesheets/_animate.scss", File.join(location, "source", options[:css_dir], "_animate.scss")
|
19
|
+
copy_file "default/source/stylesheets/_normalize.scss", File.join(location, "source", options[:css_dir], "_normalize.scss")
|
18
20
|
empty_directory File.join(location, "source", options[:js_dir])
|
21
|
+
copy_file "default/source/javascripts/all.js", File.join(location, "source", options[:js_dir], "all.js")
|
19
22
|
empty_directory File.join(location, "source", options[:images_dir])
|
23
|
+
copy_file "default/source/images/background.png", File.join(location, "source", options[:images_dir], "background.png")
|
24
|
+
copy_file "default/source/images/middleman.png", File.join(location, "source", options[:images_dir], "middleman.png")
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
Binary file
|
Binary file
|
@@ -1,5 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
---
|
2
|
+
title: Welcome to Middleman
|
3
|
+
---
|
4
4
|
|
5
|
-
<
|
5
|
+
<div class="welcome">
|
6
|
+
<h1>Middleman is Watching</h1>
|
7
|
+
<p class="doc">
|
8
|
+
<%= link_to "Read Online Documentation", "http://middlemanapp.com/" %>
|
9
|
+
</p><!-- .doc -->
|
10
|
+
</div><!-- .welcome -->
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_tree .
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
|
6
|
+
<!-- Always force latest IE rendering engine or request Chrome Frame -->
|
7
|
+
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
|
8
|
+
|
9
|
+
<!-- Use title if it's in the page YAML frontmatter -->
|
10
|
+
<title><%= data.page.title || "The Middleman" %></title>
|
11
|
+
|
12
|
+
<%= stylesheet_link_tag "all" %>
|
13
|
+
<%= javascript_include_tag "all" %>
|
14
|
+
</head>
|
15
|
+
|
16
|
+
<body class="<%= page_classes %>">
|
17
|
+
<%= yield %>
|
18
|
+
</body>
|
19
|
+
</html>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
.welcome {
|
2
|
+
-webkit-animation-name: welcome;
|
3
|
+
-webkit-animation-duration: .9s;
|
4
|
+
}
|
5
|
+
|
6
|
+
@-webkit-keyframes welcome {
|
7
|
+
from {
|
8
|
+
-webkit-transform: scale(0);
|
9
|
+
opacity: 0;
|
10
|
+
}
|
11
|
+
50% {
|
12
|
+
-webkit-transform: scale(0);
|
13
|
+
opacity: 0;
|
14
|
+
}
|
15
|
+
82.5% {
|
16
|
+
-webkit-transform: scale(1.03);
|
17
|
+
-webkit-animation-timing-function: ease-out;
|
18
|
+
opacity: 1;
|
19
|
+
}
|
20
|
+
to {
|
21
|
+
-webkit-transform: scale(1);
|
22
|
+
}
|
23
|
+
}
|