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.
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
+ }