middleman 3.0.0.alpha.3 → 3.0.0.alpha.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. data/.gitignore +1 -2
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +97 -0
  4. data/README.md +84 -13
  5. data/Rakefile +6 -2
  6. data/bin/middleman +5 -4
  7. data/features/builder.feature +7 -0
  8. data/features/clean_build.feature +11 -0
  9. data/features/current_page_request_path_backwards.feature +6 -0
  10. data/features/front-matter.feature +28 -1
  11. data/features/generator.feature +4 -4
  12. data/features/helpers_external.feature +6 -0
  13. data/features/helpers_lorem.feature +5 -0
  14. data/features/instance_vars.feature +20 -0
  15. data/features/markdown.feature +23 -3
  16. data/features/minify_css.feature +6 -1
  17. data/features/minify_javascript.feature +33 -1
  18. data/features/mount_rack.feature +8 -0
  19. data/features/partials.feature +7 -1
  20. data/features/preview_changes.feature +18 -0
  21. data/features/wildcard_page_helper.feature +19 -0
  22. data/fixtures/build-with-errors-app/config.rb +1 -0
  23. data/fixtures/build-with-errors-app/source/index.html.erb +1 -0
  24. data/fixtures/clean-app/source/index.html.haml +1 -6
  25. data/fixtures/clean-dir-app/config.rb +2 -0
  26. data/fixtures/clean-dir-app/source/about.html +1 -0
  27. data/fixtures/different-engine-partial/config.rb +0 -0
  28. data/fixtures/different-engine-partial/source/index.html.erb +1 -0
  29. data/fixtures/different-engine-partial/source/layouts/layout.erb +7 -0
  30. data/fixtures/different-engine-partial/source/shared/_footer.slim +1 -0
  31. data/fixtures/different-engine-partial/source/shared/_header.erb +1 -0
  32. data/fixtures/external-helpers/config.rb +4 -0
  33. data/fixtures/external-helpers/lib/hello_helper.rb +5 -0
  34. data/fixtures/external-helpers/source/index.html.erb +1 -0
  35. data/fixtures/instance-vars-app/config.rb +0 -0
  36. data/fixtures/instance-vars-app/source/_vartial.erb +5 -0
  37. data/fixtures/instance-vars-app/source/instance-var-set.html.erb +2 -0
  38. data/fixtures/instance-vars-app/source/layout.erb +3 -0
  39. data/fixtures/instance-vars-app/source/no-instance-var.html.erb +1 -0
  40. data/fixtures/markdown-app/config.rb +9 -0
  41. data/fixtures/markdown-app/source/autolink.html.markdown +5 -0
  42. data/fixtures/markdown-app/source/fenced_code_blocks.html.markdown +7 -0
  43. data/fixtures/markdown-app/source/index.html.markdown +4 -0
  44. data/fixtures/markdown-app/source/no_intra_emphasis.html.markdown +5 -0
  45. data/fixtures/markdown-app/source/smarty_pants.html.markdown +5 -0
  46. data/fixtures/markdown-app/source/space_after_headers.html.markdown +5 -0
  47. data/fixtures/markdown-app/source/strikethrough.html.markdown +5 -0
  48. data/fixtures/markdown-app/source/superscript.html.markdown +5 -0
  49. data/fixtures/markdown-app/source/tables.html.markdown +8 -0
  50. data/fixtures/passthrough-app/config.rb +17 -0
  51. data/fixtures/passthrough-app/source/.htaccess +1 -0
  52. data/fixtures/passthrough-app/source/inline-coffeescript.html.haml +3 -0
  53. data/fixtures/passthrough-app/source/inline-css.html.haml +4 -0
  54. data/fixtures/passthrough-app/source/inline-js.html.haml +7 -0
  55. data/fixtures/passthrough-app/source/javascripts/coffee_test.js.coffee +3 -0
  56. data/fixtures/passthrough-app/source/javascripts/js_test.js +8 -0
  57. data/fixtures/passthrough-app/source/stylesheets/site.css.sass +1 -0
  58. data/fixtures/preview-app/config.rb +0 -0
  59. data/fixtures/preview-app/source/content.html.erb +1 -0
  60. data/fixtures/preview-app/source/layout.erb +1 -0
  61. data/fixtures/sinatra-app/config.rb +11 -0
  62. data/fixtures/sinatra-app/source/index.html.erb +5 -0
  63. data/fixtures/test-app/config.rb +2 -2
  64. data/fixtures/test-app/source/front-matter-2.php.erb +7 -0
  65. data/fixtures/test-app/source/front-matter-change.html.erb +5 -0
  66. data/fixtures/test-app/source/index.html.slim +9 -0
  67. data/fixtures/test-app/source/javascripts/js_test.js +8 -0
  68. data/fixtures/test-app/source/lorem.html.erb +12 -0
  69. data/fixtures/test-app/source/request-path.html.erb +1 -0
  70. data/fixtures/wildcard-app/config.rb +1 -0
  71. data/fixtures/wildcard-app/source/admin/index.html.erb +1 -0
  72. data/fixtures/wildcard-app/source/admin/page.html.erb +1 -0
  73. data/fixtures/wildcard-app/source/index.html.erb +1 -0
  74. data/fixtures/wildcard-app/source/layouts/admin.erb +2 -0
  75. data/fixtures/wildcard-app/source/layouts/layout.erb +2 -0
  76. data/fixtures/wildcard-directory-index-app/config.rb +2 -0
  77. data/fixtures/wildcard-directory-index-app/source/admin/index.html.erb +1 -0
  78. data/fixtures/wildcard-directory-index-app/source/admin/page.html.erb +1 -0
  79. data/fixtures/wildcard-directory-index-app/source/index.html.erb +1 -0
  80. data/fixtures/wildcard-directory-index-app/source/layouts/admin.erb +2 -0
  81. data/fixtures/wildcard-directory-index-app/source/layouts/layout.erb +2 -0
  82. data/lib/middleman.rb +63 -8
  83. data/lib/middleman/base.rb +56 -12
  84. data/lib/middleman/builder.rb +18 -12
  85. data/lib/middleman/cli.rb +5 -5
  86. data/lib/middleman/core_extensions/assets.rb +12 -0
  87. data/lib/middleman/core_extensions/builder.rb +4 -4
  88. data/lib/middleman/core_extensions/extensions.rb +5 -51
  89. data/lib/middleman/core_extensions/front_matter.rb +30 -11
  90. data/lib/middleman/core_extensions/rendering.rb +18 -12
  91. data/lib/middleman/core_extensions/routing.rb +12 -0
  92. data/lib/middleman/core_extensions/show_exceptions.rb +16 -0
  93. data/lib/middleman/core_extensions/sitemap.rb +10 -4
  94. data/lib/middleman/extensions/minify_css.rb +4 -2
  95. data/lib/middleman/extensions/minify_javascript.rb +8 -6
  96. data/lib/middleman/guard.rb +80 -76
  97. data/lib/middleman/renderers/markdown.rb +8 -13
  98. data/lib/middleman/sitemap/page.rb +3 -2
  99. data/lib/middleman/sitemap/store.rb +3 -1
  100. data/lib/middleman/sitemap/template.rb +19 -5
  101. data/lib/middleman/step_definitions.rb +1 -0
  102. data/lib/middleman/step_definitions/builder_steps.rb +6 -1
  103. data/lib/middleman/step_definitions/generator_steps.rb +9 -13
  104. data/lib/middleman/step_definitions/middleman_steps.rb +13 -0
  105. data/lib/middleman/step_definitions/server_steps.rb +7 -0
  106. data/lib/middleman/templates.rb +42 -21
  107. data/lib/middleman/templates/default.rb +5 -0
  108. data/lib/middleman/templates/html5.rb +6 -0
  109. data/lib/middleman/templates/local.rb +5 -6
  110. data/lib/middleman/templates/mobile.rb +6 -0
  111. data/lib/middleman/version.rb +1 -1
  112. data/middleman-x86-mingw32.gemspec +1 -1
  113. data/middleman.gemspec +3 -2
  114. metadata +531 -242
  115. data/CHANGELOG +0 -98
  116. data/fixtures/test-app/source/index.html.haml +0 -9
  117. data/fixtures/test-app/source/markdown.html.markdown +0 -1
@@ -39,10 +39,13 @@ module Middleman::CoreExtensions::Rendering
39
39
  engine = extension[1..-1].to_sym
40
40
 
41
41
  @current_engine, engine_was = engine, @current_engine
42
- @_out_buf, _buf_was = "", @_out_buf
43
42
 
43
+ # Use a dup of self as a context so that instance variables set within
44
+ # the template don't persist for other templates.
45
+ context = self.dup
46
+
44
47
  while ::Tilt[path]
45
- content = render_individual_file(path, locs, opts)
48
+ content = render_individual_file(path, locs, opts, context)
46
49
  path = File.basename(path, File.extname(path))
47
50
  cache.set([:raw_template, path], content)
48
51
  end
@@ -50,13 +53,12 @@ module Middleman::CoreExtensions::Rendering
50
53
  needs_layout = !%w(.js .css .txt).include?(extension)
51
54
 
52
55
  if needs_layout && layout_path = fetch_layout(engine, opts)
53
- content = render_individual_file(layout_path, locs, opts) { content }
56
+ content = render_individual_file(layout_path, locs, opts, context) { content }
54
57
  end
55
58
 
56
59
  content
57
60
  ensure
58
61
  @current_engine = engine_was
59
- @_out_buf = _buf_was
60
62
  @content_blocks = nil
61
63
  end
62
64
 
@@ -94,16 +96,18 @@ module Middleman::CoreExtensions::Rendering
94
96
  end
95
97
 
96
98
  if found_partial
97
- render_individual_file(found_partial, locals, options, &block)
99
+ render_individual_file(found_partial, locals, options, self, &block)
98
100
  else
99
101
  raise ::Middleman::CoreExtensions::Rendering::TemplateNotFound, "Could not locate partial: #{data}"
100
102
  end
101
103
  end
102
104
 
103
105
  # @private
104
- def render_individual_file(path, locs = {}, opts = {}, &block)
106
+ def render_individual_file(path, locs = {}, opts = {}, context = self, &block)
105
107
  path = path.to_s
106
108
 
109
+ @_out_buf, _buf_was = "", @_out_buf
110
+
107
111
  body = cache.fetch(:raw_template, path) do
108
112
  File.read(path)
109
113
  end
@@ -116,7 +120,9 @@ module Middleman::CoreExtensions::Rendering
116
120
  ::Tilt.new(path, 1, options) { body }
117
121
  end
118
122
 
119
- template.render(self, locs, &block)
123
+ template.render(context, locs, &block)
124
+ ensure
125
+ @_out_buf = _buf_was
120
126
  end
121
127
 
122
128
  # @private
@@ -169,11 +175,11 @@ module Middleman::CoreExtensions::Rendering
169
175
  # @private
170
176
  def locate_layout(name, preferred_engine=nil)
171
177
  layout_path = false
172
-
178
+
173
179
  if !preferred_engine.nil?
174
180
  # Check root
175
181
  layout_path, layout_engine = resolve_template(name, :preferred_engine => preferred_engine)
176
-
182
+
177
183
  # Check layouts folder
178
184
  if !layout_path
179
185
  layout_path, layout_engine = resolve_template(File.join("layouts", name.to_s), :preferred_engine => preferred_engine)
@@ -227,8 +233,8 @@ module Middleman::CoreExtensions::Rendering
227
233
  found_path = Dir[path_with_ext].find do |path|
228
234
  ::Tilt[path]
229
235
  end
230
-
231
- if found_path || File.exists?(on_disk_path)
236
+
237
+ if found_path || (File.exists?(on_disk_path) && !File.directory?(on_disk_path))
232
238
  engine = found_path ? File.extname(found_path)[1..-1].to_sym : nil
233
239
  [ found_path || on_disk_path, engine ]
234
240
  else
@@ -237,4 +243,4 @@ module Middleman::CoreExtensions::Rendering
237
243
  end
238
244
  end
239
245
  end
240
- end
246
+ end
@@ -25,6 +25,18 @@ module Middleman::CoreExtensions::Routing
25
25
  # page "/about.html", :layout => false
26
26
  # page "/", :layout => :homepage_layout
27
27
  def page(url, opts={}, &block)
28
+ if url.include?("*")
29
+ url = Regexp.new(url.gsub("*", "(.*)").gsub(/^\//, "^"))
30
+ end
31
+
32
+ if url.is_a?(Regexp) && !opts.empty?
33
+ provides_metadata_for_path url do |url|
34
+ { :options => opts }
35
+ end
36
+
37
+ return
38
+ end
39
+
28
40
  opts[:layout] = layout if opts[:layout].nil?
29
41
 
30
42
  url = full_path(url)
@@ -0,0 +1,16 @@
1
+ require 'rack/showexceptions'
2
+
3
+ module Middleman::CoreExtensions::ShowExceptions
4
+ class << self
5
+ def registered(app)
6
+ app.configure :development do
7
+ if show_exceptions
8
+ use ::Middleman::CoreExtensions::ShowExceptions::Middleware
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ class Middleware < ::Rack::ShowExceptions
15
+ end
16
+ end
@@ -12,12 +12,12 @@ module Middleman::CoreExtensions::Sitemap
12
12
  module InstanceMethods
13
13
  def initialize
14
14
  super
15
-
16
- file_changed do |file|
15
+
16
+ file_changed %r{^source/} do |file|
17
17
  sitemap.touch_file(file)
18
18
  end
19
-
20
- file_deleted do |file|
19
+
20
+ file_deleted %r{^source/} do |file|
21
21
  sitemap.remove_file(file)
22
22
  end
23
23
  end
@@ -40,5 +40,11 @@ module Middleman::CoreExtensions::Sitemap
40
40
  @_provides_metadata << [block, matcher] if block_given?
41
41
  @_provides_metadata
42
42
  end
43
+
44
+ def provides_metadata_for_path(matcher=nil, &block)
45
+ @_provides_metadata_for_path ||= []
46
+ @_provides_metadata_for_path << [block, matcher] if block_given?
47
+ @_provides_metadata_for_path
48
+ end
43
49
  end
44
50
  end
@@ -2,9 +2,11 @@ module Middleman::Extensions
2
2
  module MinifyCss
3
3
  class << self
4
4
  def registered(app)
5
- require "middleman/extensions/minify_css/cssmin"
6
5
  app.after_configuration do
7
- set :css_compressor, ::CSSMin
6
+ if !css_compressor
7
+ require "middleman/extensions/minify_css/cssmin"
8
+ set :css_compressor, ::CSSMin
9
+ end
8
10
  end
9
11
  end
10
12
  alias :included :registered
@@ -2,11 +2,14 @@ module Middleman::Extensions
2
2
  module MinifyJavascript
3
3
  class << self
4
4
  def registered(app)
5
- require 'uglifier'
6
5
  app.after_configuration do
7
- set :js_compressor, ::Uglifier.new
6
+ if !js_compressor
7
+ require 'uglifier'
8
+ set :js_compressor, ::Uglifier.new
9
+ end
10
+
11
+ use InlineJavascriptRack, :compressor => js_compressor
8
12
  end
9
- app.use InlineJavascriptRack
10
13
  end
11
14
  alias :included :registered
12
15
  end
@@ -14,14 +17,13 @@ module Middleman::Extensions
14
17
  class InlineJavascriptRack
15
18
  def initialize(app, options={})
16
19
  @app = app
20
+ @compressor = options[:compressor]
17
21
  end
18
22
 
19
23
  def call(env)
20
24
  status, headers, response = @app.call(env)
21
25
 
22
26
  if env["PATH_INFO"].match(/\.html$/)
23
- compressor = ::Uglifier.new
24
-
25
27
  uncompressed_source = case(response)
26
28
  when String
27
29
  response
@@ -37,7 +39,7 @@ module Middleman::Extensions
37
39
  first = $1
38
40
  uncompressed_source = $2
39
41
  last = $3
40
- minified_js = compressor.compile(uncompressed_source)
42
+ minified_js = @compressor.compress(uncompressed_source)
41
43
 
42
44
  first << minified_js << "\n" << last
43
45
  end
@@ -1,85 +1,50 @@
1
+ # Guard watches the filesystem for changes
1
2
  require "guard"
2
3
  require "guard/guard"
3
- require "rbconfig"
4
+
5
+ # File changes are forwarded to the currently running app via HTTP
4
6
  require "net/http"
5
7
 
6
- if RbConfig::CONFIG['host_os'].downcase =~ %r{mingw}
7
- require "win32/process"
8
- end
8
+ # Support forking on Windows
9
+ require "rbconfig"
10
+ require "win32/process" if RbConfig::CONFIG['host_os'].downcase =~ %r{mingw}
9
11
 
10
- module Middleman
11
- module Guard
12
- class << self
13
- def add_guard(&block)
14
- # Deprecation Warning
15
- puts "== Middleman::Guard.add_guard has been removed. Update your extensions to versions which support this change."
16
- end
12
+ module Middleman::Guard
13
+ def self.start(options={})
14
+ # Forward CLI options to Guard
15
+ options_hash = options.map { |k,v| ", :#{k} => '#{v}'" }.join
17
16
 
18
- def start(options={})
19
- options_hash = ""
20
- options.each do |k,v|
21
- options_hash << ", :#{k} => '#{v}'"
17
+ # Watch all files in project, even hidden ones.
18
+ ::Guard.start({
19
+ :guardfile_contents => %Q{
20
+ guard 'middleman'#{options_hash} do
21
+ watch(%r{(.*)})
22
22
  end
23
-
24
- guardfile_contents = %Q{
25
- guard 'middleman'#{options_hash} do
26
- watch(%r{(.*)})
27
- end
28
- }
29
-
30
- ::Guard.start({ :guardfile_contents => guardfile_contents })
31
- end
32
- end
23
+ },
24
+ :watch_all_modifications => true
25
+ })
33
26
  end
34
27
  end
35
28
 
36
29
  # @private
37
30
  module Guard
31
+ # Monkeypatch Guard into being quiet
32
+ module UI
33
+ class << self
34
+ def info(message, options = { }); end
35
+ end
36
+ end
37
+
38
+ # Guards must be in the Guard module to be picked up
38
39
  class Middleman < Guard
40
+ # Save the options for later
39
41
  def initialize(watchers = [], options = {})
40
42
  super
41
43
  @options = options
42
44
  end
43
45
 
46
+ # Start Middleman in a fork
44
47
  def start
45
- server_start
46
- end
47
-
48
- def reload
49
- server_stop
50
- server_start
51
- end
52
-
53
- def run_on_change(paths)
54
- needs_to_restart = false
55
-
56
- paths.each do |path|
57
- if path.match(%{^config\.rb}) || path.match(%r{^lib/^[^\.](.*)\.rb$})
58
- needs_to_restart = true
59
- break
60
- end
61
- end
62
-
63
- if needs_to_restart
64
- reload
65
- else
66
- paths.each do |path|
67
- file_did_change(path)
68
- end
69
- end
70
- end
71
-
72
- def run_on_deletion(paths)
73
- paths.each do |path|
74
- file_did_delete(path)
75
- end
76
- end
77
-
78
- private
79
- def server_start
80
- # Quiet down Guard
81
- # ENV['GUARD_ENV'] = 'test' if @options[:debug] == "true"
82
-
83
48
  @server_job = fork do
84
49
  env = (@options[:environment] || "development").to_sym
85
50
  is_logging = @options.has_key?(:debug) && (@options[:debug] == "true")
@@ -87,35 +52,74 @@ module Guard
87
52
  set :environment, env
88
53
  set :logging, is_logging
89
54
  end
90
-
55
+
56
+ require "thin"
57
+ ::Thin::Logging.silent = !is_logging
58
+
91
59
  app_rack = app.class.to_rack_app
92
-
60
+
93
61
  opts = @options.dup
94
62
  opts[:app] = app_rack
95
63
  puts "== The Middleman is standing watch on port #{opts[:port]||4567}"
96
64
  ::Middleman.start_server(opts)
97
65
  end
98
66
  end
99
-
100
- def server_stop
67
+
68
+ # Stop the forked Middleman
69
+ def stop
101
70
  puts "== The Middleman is shutting down"
102
71
  Process.kill("KILL", @server_job)
103
72
  Process.wait @server_job
104
73
  @server_job = nil
105
- # @app = nil
106
74
  end
107
75
 
108
- def talk_to_server(params={})
109
- uri = URI.parse("http://#{@options[:host]}:#{@options[:port]}/__middleman__")
110
- Net::HTTP.post_form(uri, {}.merge(params))
76
+ # Simply stop, then start
77
+ def reload
78
+ stop
79
+ start
111
80
  end
112
-
113
- def file_did_change(path)
114
- talk_to_server :change => path
81
+
82
+ # What to do on file change
83
+ # @param [Array<String>] paths Array of paths that changed
84
+ def run_on_change(paths)
85
+ # See if the changed file is config.rb or lib/*.rb
86
+ return reload if needs_to_reload?(paths)
87
+
88
+ # Otherwise forward to Middleman
89
+ paths.each { |path| tell_server(:change => path) }
90
+ end
91
+
92
+ # What to do on file deletion
93
+ # @param [Array<String>] paths Array of paths that were removed
94
+ def run_on_deletion(paths)
95
+ # See if the changed file is config.rb or lib/*.rb
96
+ return reload if needs_to_reload?(paths)
97
+
98
+ # Otherwise forward to Middleman
99
+ paths.each { |path| tell_server(:delete => path) }
115
100
  end
116
101
 
117
- def file_did_delete(path)
118
- talk_to_server :delete => path
102
+ private
103
+ # Whether the passed files are config.rb or lib/*.rb
104
+ # @param [Array<String>] paths Array of paths to check
105
+ # @return [Boolean] Whether the server needs to reload
106
+ def needs_to_reload?(paths)
107
+ paths.any? do |path|
108
+ path.match(%{^config\.rb}) || path.match(%r{^lib/^[^\.](.*)\.rb$})
109
+ end
110
+ end
111
+
112
+ # Send a message to the running server
113
+ # @param [Hash] params Keys to be hashed and sent to server
114
+ def tell_server(params={})
115
+ uri = URI.parse("http://#{@options[:host]}:#{@options[:port]}/__middleman__")
116
+ Net::HTTP.post_form(uri, {}.merge(params))
119
117
  end
120
118
  end
119
+ end
120
+
121
+ # Trap the interupt signal and shut down Guard (and thus the server) smoothly
122
+ trap(:INT) do
123
+ ::Guard.stop
124
+ exit
121
125
  end
@@ -1,19 +1,14 @@
1
1
  module Middleman::Renderers::Markdown
2
2
  class << self
3
3
  def registered(app)
4
- app.set :markdown_engine, nil
5
-
6
- begin
7
- require "maruku"
8
- app.set :markdown_engine, :maruku
9
- rescue LoadError
10
- begin
11
- require "rdiscount"
12
- app.set :markdown_engine, :rdiscount
13
- rescue LoadError
14
- end
15
- end
16
-
4
+ require "redcarpet"
5
+
6
+ # Forcably disable Redcarpet1 support.
7
+ # Tilt defaults to this if available, but the compat
8
+ # layer disables extensions.
9
+ Object.send(:remove_const, :RedcarpetCompat) if defined? ::RedcarpetCompat
10
+
11
+ app.set :markdown_engine, :redcarpet
17
12
  app.set :markdown_engine_prefix, ::Tilt
18
13
 
19
14
  app.after_configuration do
@@ -69,9 +69,10 @@ module Middleman::Sitemap
69
69
  end
70
70
 
71
71
  def touch
72
+ template.touch if template?
72
73
  end
73
74
 
74
- def custom_render(&block)
75
+ def custom_renderer(&block)
75
76
  @_custom_renderer ||= nil
76
77
  @_custom_renderer = block if block_given?
77
78
  @_custom_renderer
@@ -89,7 +90,7 @@ module Middleman::Sitemap
89
90
  instance_exec(&block)
90
91
  end
91
92
  end
92
- elsif !custom_render.nil?
93
+ elsif !custom_renderer.nil?
93
94
  params = args.dup
94
95
  params << block if block_given?
95
96
  instance_exec(*params, &custom_renderer)