middleman 3.0.0.alpha.5 → 3.0.0.alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/CHANGELOG.md +3 -2
  2. data/README.md +7 -7
  3. data/bin/middleman +3 -2
  4. data/features/builder.feature +4 -0
  5. data/features/cli.feature +10 -11
  6. data/features/nested_layouts.feature +24 -0
  7. data/features/sitemap_traversal.features +56 -0
  8. data/fixtures/empty-app/not-config.rb +0 -0
  9. data/fixtures/nested-layout-app/config.rb +1 -0
  10. data/fixtures/nested-layout-app/source/data-one.html.erb +5 -0
  11. data/fixtures/nested-layout-app/source/data-two.html.erb +5 -0
  12. data/fixtures/nested-layout-app/source/index.html.erb +1 -0
  13. data/fixtures/nested-layout-app/source/layouts/inner.erb +4 -0
  14. data/fixtures/nested-layout-app/source/layouts/master.erb +3 -0
  15. data/fixtures/nested-layout-app/source/layouts/outer.erb +4 -0
  16. data/fixtures/traversal-app/config.rb +2 -0
  17. data/fixtures/traversal-app/source/index.html.erb +0 -0
  18. data/fixtures/traversal-app/source/layout.erb +13 -0
  19. data/fixtures/traversal-app/source/proxied.html.erb +0 -0
  20. data/fixtures/traversal-app/source/root.html.erb +0 -0
  21. data/fixtures/traversal-app/source/sub/index.html.erb +0 -0
  22. data/fixtures/traversal-app/source/sub/sibling.html.erb +0 -0
  23. data/fixtures/traversal-app/source/sub/sibling2.html.erb +0 -0
  24. data/fixtures/traversal-app/source/sub/sub2/index.html.erb +0 -0
  25. data/fixtures/traversal-app/source/sub/sub3/deep.html.erb +0 -0
  26. data/lib/middleman.rb +0 -3
  27. data/lib/middleman/base.rb +3 -28
  28. data/lib/middleman/cli/server.rb +0 -1
  29. data/lib/middleman/core_extensions/builder.rb +1 -7
  30. data/lib/middleman/core_extensions/default_helpers.rb +27 -1
  31. data/lib/middleman/core_extensions/extensions.rb +20 -4
  32. data/lib/middleman/core_extensions/file_watcher.rb +25 -8
  33. data/lib/middleman/core_extensions/front_matter.rb +5 -12
  34. data/lib/middleman/core_extensions/rendering.rb +10 -0
  35. data/lib/middleman/core_extensions/sitemap.rb +4 -0
  36. data/lib/middleman/guard.rb +11 -11
  37. data/lib/middleman/sitemap/page.rb +55 -0
  38. data/lib/middleman/sitemap/template.rb +9 -3
  39. data/lib/middleman/step_definitions.rb +0 -1
  40. data/lib/middleman/templates/default.rb +7 -2
  41. data/lib/middleman/templates/default/source/images/background.png +0 -0
  42. data/lib/middleman/templates/default/source/images/middleman.png +0 -0
  43. data/lib/middleman/templates/default/source/index.html.erb +9 -4
  44. data/lib/middleman/templates/default/source/javascripts/all.js +1 -0
  45. data/lib/middleman/templates/default/source/layouts/layout.erb +19 -0
  46. data/lib/middleman/templates/default/source/stylesheets/_animate.scss +23 -0
  47. data/lib/middleman/templates/default/source/stylesheets/_normalize.scss +431 -0
  48. data/lib/middleman/templates/default/source/stylesheets/all.css.scss +40 -0
  49. data/lib/middleman/templates/shared/config.tt +4 -16
  50. data/lib/middleman/version.rb +1 -1
  51. data/middleman-x86-mingw32.gemspec +1 -1
  52. data/middleman.gemspec +1 -1
  53. metadata +54 -13
  54. data/features/generator.feature +0 -8
  55. data/lib/middleman/extensions/sitemap_tree.rb +0 -38
  56. data/lib/middleman/step_definitions/generator_steps.rb +0 -26
  57. data/lib/middleman/templates/default/source/layout.erb +0 -19
  58. 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
- def file_changed(*args, &block)
43
- self.class.file_changed(*args, &block)
44
- end
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
- data = if frontmatter.has_data?(relative_path)
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
- # Forward remaining data to helpers
47
- data_content("page", data)
48
-
47
+ data = {}
49
48
  %w(layout layout_engine).each do |opt|
50
- if data.has_key?(opt)
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
@@ -26,6 +26,10 @@ module Middleman::CoreExtensions::Sitemap
26
26
  @sitemap ||= ::Middleman::Sitemap::Store.new(self)
27
27
  end
28
28
 
29
+ def current_page
30
+ sitemap.page(current_path)
31
+ end
32
+
29
33
  # Keep a path from building
30
34
  def ignore(path)
31
35
  sitemap.ignore(path)
@@ -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(kill_command, @server_job)
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
- opts = options.deep_merge(metadata[:options]).deep_merge(opts)
61
- locs = locals.deep_merge(metadata[:locals]).deep_merge(locs)
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/site.css.scss", File.join(location, "source", options[:css_dir], "site.css.scss")
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
 
@@ -1,5 +1,10 @@
1
- <% content_for :head do %>
2
- <title>The Middleman!</title>
3
- <% end %>
1
+ ---
2
+ title: Welcome to Middleman
3
+ ---
4
4
 
5
- <h1>The Middleman is watching.</h1>
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,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
+ }