middleman-core 3.2.1 → 3.2.2

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/features/helpers_select_tag.feature +19 -0
  4. data/lib/middleman-core.rb +4 -4
  5. data/lib/middleman-core/application.rb +40 -46
  6. data/lib/middleman-core/cli.rb +15 -15
  7. data/lib/middleman-core/cli/build.rb +26 -24
  8. data/lib/middleman-core/cli/bundler.rb +4 -4
  9. data/lib/middleman-core/cli/console.rb +6 -6
  10. data/lib/middleman-core/cli/extension.rb +12 -12
  11. data/lib/middleman-core/cli/init.rb +17 -17
  12. data/lib/middleman-core/cli/server.rb +28 -28
  13. data/lib/middleman-core/configuration.rb +2 -2
  14. data/lib/middleman-core/core_extensions.rb +23 -23
  15. data/lib/middleman-core/core_extensions/data.rb +5 -5
  16. data/lib/middleman-core/core_extensions/extensions.rb +6 -6
  17. data/lib/middleman-core/core_extensions/external_helpers.rb +2 -2
  18. data/lib/middleman-core/core_extensions/file_watcher.rb +3 -3
  19. data/lib/middleman-core/core_extensions/front_matter.rb +11 -11
  20. data/lib/middleman-core/core_extensions/rendering.rb +21 -21
  21. data/lib/middleman-core/core_extensions/request.rb +10 -8
  22. data/lib/middleman-core/core_extensions/routing.rb +1 -1
  23. data/lib/middleman-core/extensions.rb +5 -5
  24. data/lib/middleman-core/load_paths.rb +7 -7
  25. data/lib/middleman-core/logger.rb +13 -1
  26. data/lib/middleman-core/meta_pages.rb +2 -2
  27. data/lib/middleman-core/meta_pages/config_setting.rb +3 -3
  28. data/lib/middleman-core/meta_pages/sitemap_resource.rb +2 -2
  29. data/lib/middleman-core/meta_pages/sitemap_tree.rb +4 -4
  30. data/lib/middleman-core/preview_server.rb +16 -12
  31. data/lib/middleman-core/profiling.rb +1 -1
  32. data/lib/middleman-core/renderers/coffee_script.rb +1 -1
  33. data/lib/middleman-core/renderers/erb.rb +1 -1
  34. data/lib/middleman-core/renderers/haml.rb +1 -1
  35. data/lib/middleman-core/renderers/kramdown.rb +2 -2
  36. data/lib/middleman-core/renderers/less.rb +2 -2
  37. data/lib/middleman-core/renderers/liquid.rb +1 -1
  38. data/lib/middleman-core/renderers/markdown.rb +3 -3
  39. data/lib/middleman-core/renderers/redcarpet.rb +1 -1
  40. data/lib/middleman-core/renderers/sass.rb +7 -7
  41. data/lib/middleman-core/renderers/slim.rb +2 -2
  42. data/lib/middleman-core/renderers/stylus.rb +2 -2
  43. data/lib/middleman-core/sitemap.rb +8 -8
  44. data/lib/middleman-core/sitemap/extensions/ignores.rb +2 -2
  45. data/lib/middleman-core/sitemap/extensions/redirects.rb +4 -1
  46. data/lib/middleman-core/sitemap/extensions/traversal.rb +6 -6
  47. data/lib/middleman-core/sitemap/queryable.rb +3 -3
  48. data/lib/middleman-core/sitemap/resource.rb +6 -6
  49. data/lib/middleman-core/sitemap/store.rb +12 -12
  50. data/lib/middleman-core/step_definitions.rb +5 -5
  51. data/lib/middleman-core/step_definitions/builder_steps.rb +5 -5
  52. data/lib/middleman-core/step_definitions/server_steps.rb +6 -6
  53. data/lib/middleman-core/templates.rb +14 -14
  54. data/lib/middleman-core/templates/default.rb +17 -17
  55. data/lib/middleman-core/templates/empty.rb +3 -3
  56. data/lib/middleman-core/templates/extension/Gemfile +7 -7
  57. data/lib/middleman-core/templates/extension/Rakefile +1 -1
  58. data/lib/middleman-core/templates/extension/features/support/env.rb +2 -2
  59. data/lib/middleman-core/templates/extension/lib/lib.rb +2 -2
  60. data/lib/middleman-core/templates/extension/lib/middleman_extension.rb +1 -1
  61. data/lib/middleman-core/templates/html5.rb +9 -9
  62. data/lib/middleman-core/templates/local.rb +3 -3
  63. data/lib/middleman-core/templates/mobile.rb +6 -6
  64. data/lib/middleman-core/templates/shared/config.tt +1 -1
  65. data/lib/middleman-core/util.rb +234 -182
  66. data/lib/middleman-core/version.rb +1 -1
  67. data/lib/middleman-more/core_extensions/compass.rb +3 -3
  68. data/lib/middleman-more/core_extensions/default_helpers.rb +21 -10
  69. data/lib/middleman-more/core_extensions/i18n.rb +18 -18
  70. data/lib/middleman-more/extensions/asset_hash.rb +7 -5
  71. data/lib/middleman-more/extensions/asset_host.rb +2 -2
  72. data/lib/middleman-more/extensions/automatic_alt_tags.rb +4 -4
  73. data/lib/middleman-more/extensions/automatic_image_sizes.rb +3 -3
  74. data/lib/middleman-more/extensions/cache_buster.rb +7 -7
  75. data/lib/middleman-more/extensions/lorem.rb +5 -5
  76. data/lib/middleman-more/extensions/minify_css.rb +4 -4
  77. data/lib/middleman-more/extensions/minify_javascript.rb +3 -3
  78. data/lib/middleman-more/extensions/relative_assets.rb +1 -1
  79. data/lib/middleman-more/templates/smacss.rb +10 -10
  80. data/lib/middleman/rack.rb +2 -2
  81. data/middleman-core.gemspec +1 -1
  82. metadata +6 -4
@@ -24,7 +24,7 @@
24
24
  # page "/admin/*"
25
25
  # end
26
26
 
27
- # Proxy pages (http://middlemanapp.com/dynamic-pages/)
27
+ # Proxy pages (http://middlemanapp.com/basics/dynamic-pages/)
28
28
  # proxy "/this-page-has-no-template.html", "/template-file.html", :locals => {
29
29
  # :which_fake_page => "Rendering a fake page with a local variable" }
30
30
 
@@ -1,202 +1,269 @@
1
- # Our custom logger
2
- require "middleman-core/logger"
3
-
4
1
  # For instrumenting
5
- require "active_support/notifications"
2
+ require 'active_support/notifications'
6
3
 
7
4
  # Using Thor's indifferent hash access
8
- require "thor"
5
+ require 'thor'
9
6
 
10
7
  # Core Pathname library used for traversal
11
- require "pathname"
8
+ require 'pathname'
12
9
 
13
- require "tilt"
14
- require "rack/mime"
10
+ # Template and Mime detection
11
+ require 'tilt'
12
+ require 'rack/mime'
15
13
 
16
14
  module Middleman
17
-
18
15
  module Util
16
+ class << self
19
17
 
20
- # Whether the source file is binary.
21
- #
22
- # @param [String] filename The file to check.
23
- # @return [Boolean]
24
- def self.binary?(filename)
25
- ext = File.extname(filename)
26
- return true if ext == '.svgz'
27
- return false if Tilt.registered?(ext.sub('.',''))
28
-
29
- ext = ".#{ext}" unless ext.to_s[0] == ?.
30
- mime = ::Rack::Mime.mime_type(ext, nil)
31
- unless mime
32
- binary_bytes = [0, 1, 2, 3, 4, 5, 6, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31]
33
- s = File.read(filename, 4096) || ''
34
- s.each_byte do |c|
35
- return true if binary_bytes.include?(c)
18
+ # Whether the source file is binary.
19
+ #
20
+ # @param [String] filename The file to check.
21
+ # @return [Boolean]
22
+ def binary?(filename)
23
+ ext = File.extname(filename)
24
+
25
+ # We hardcode detecting of gzipped SVG files
26
+ return true if ext == '.svgz'
27
+
28
+ return false if Tilt.registered?(ext.sub('.', ''))
29
+
30
+ dot_ext = (ext.to_s[0] == ?.) ? ext.dup : ".#{ext}"
31
+
32
+ if mime = ::Rack::Mime.mime_type(dot_ext, nil)
33
+ !nonbinary_mime?(mime)
34
+ else
35
+ file_contents_include_binary_bytes?(filename)
36
36
  end
37
- return false
38
37
  end
39
- return false if mime.start_with?('text/')
40
- return false if mime.include?('xml')
41
- return false if mime.include?('json')
42
- return false if mime.include?('javascript')
43
- true
44
- end
45
38
 
46
- # The logger
47
- #
48
- # @return [Middleman::Logger] The logger
49
- def self.logger(*args)
50
- if !@_logger || args.length > 0
51
- if args.length == 1 && (args.first.is_a?(::String) || args.first.respond_to?(:write))
52
- args = [0, false, args.first]
39
+ # Facade for ActiveSupport/Notification
40
+ def instrument(name, payload={}, &block)
41
+ suffixed_name = (name =~ /\.middleman$/) ? name.dup : "#{name}.middleman"
42
+ ::ActiveSupport::Notifications.instrument(suffixed_name, payload, &block)
43
+ end
44
+
45
+ # Recursively convert a normal Hash into a HashWithIndifferentAccess
46
+ #
47
+ # @private
48
+ # @param [Hash] data Normal hash
49
+ # @return [Thor::CoreExt::HashWithIndifferentAccess]
50
+ def recursively_enhance(data)
51
+ if data.is_a? Hash
52
+ data = ::Thor::CoreExt::HashWithIndifferentAccess.new(data)
53
+ data.each do |key, val|
54
+ data[key] = recursively_enhance(val)
55
+ end
56
+ data
57
+ elsif data.is_a? Array
58
+ data.each_with_index do |val, i|
59
+ data[i] = recursively_enhance(val)
60
+ end
61
+ data
62
+ else
63
+ data
53
64
  end
54
- @_logger = ::Middleman::Logger.new(*args)
55
65
  end
56
66
 
57
- @_logger
58
- end
67
+ # Normalize a path to not include a leading slash
68
+ # @param [String] path
69
+ # @return [String]
70
+ def normalize_path(path)
71
+ # The tr call works around a bug in Ruby's Unicode handling
72
+ path.sub(%r{^/}, '').tr('','')
73
+ end
59
74
 
60
- # Facade for ActiveSupport/Notification
61
- def self.instrument(name, payload={}, &block)
62
- name << ".middleman" unless name =~ /\.middleman$/
63
- ::ActiveSupport::Notifications.instrument(name, payload, &block)
64
- end
75
+ # This is a separate method from normalize_path in case we
76
+ # change how we normalize paths
77
+ def strip_leading_slash(path)
78
+ path.sub(%r{^/}, '')
79
+ end
65
80
 
66
- # Recursively convert a normal Hash into a HashWithIndifferentAccess
67
- #
68
- # @private
69
- # @param [Hash] data Normal hash
70
- # @return [Thor::CoreExt::HashWithIndifferentAccess]
71
- def self.recursively_enhance(data)
72
- if data.is_a? Hash
73
- data = ::Thor::CoreExt::HashWithIndifferentAccess.new(data)
74
- data.each do |key, val|
75
- data[key] = recursively_enhance(val)
81
+ # Extract the text of a Rack response as a string.
82
+ # Useful for extensions implemented as Rack middleware.
83
+ # @param response The response from #call
84
+ # @return [String] The whole response as a string.
85
+ def extract_response_text(response)
86
+ # The rack spec states all response bodies must respond to each
87
+ result = ''
88
+ response.each do |part, s|
89
+ result << part
76
90
  end
77
- data
78
- elsif data.is_a? Array
79
- data.each_with_index do |val, i|
80
- data[i] = recursively_enhance(val)
81
- end
82
- data
83
- else
84
- data
91
+ result
85
92
  end
86
- end
87
93
 
88
- # Normalize a path to not include a leading slash
89
- # @param [String] path
90
- # @return [String]
91
- def self.normalize_path(path)
92
- # The tr call works around a bug in Ruby's Unicode handling
93
- path.sub(%r{^/}, "").tr('','')
94
- end
94
+ # Takes a matcher, which can be a literal string
95
+ # or a string containing glob expressions, or a
96
+ # regexp, or a proc, or anything else that responds
97
+ # to #match or #call, and returns whether or not the
98
+ # given path matches that matcher.
99
+ #
100
+ # @param matcher A matcher string/regexp/proc/etc
101
+ # @param path A path as a string
102
+ # @return [Boolean] Whether the path matches the matcher
103
+ def path_match(matcher, path)
104
+ case
105
+ when matcher.is_a?(String)
106
+ path.match(matcher)
107
+ when matcher.respond_to?(:match)
108
+ matcher.match(path)
109
+ when matcher.respond_to?(:call)
110
+ matcher.call(path)
111
+ else
112
+ File.fnmatch(matcher.to_s, path)
113
+ end
114
+ end
95
115
 
96
- # This is a separate method from normalize_path in case we
97
- # change how we normalize paths
98
- def self.strip_leading_slash(path)
99
- path.sub(%r{^/}, "")
100
- end
116
+ # Get a recusive list of files inside a set of paths.
117
+ # Works with symlinks.
118
+ #
119
+ # @param paths Some paths string or Pathname
120
+ # @return [Array] An array of filenames
121
+ def all_files_under(*paths)
122
+ paths.flat_map do |p|
123
+ path = Pathname(p)
101
124
 
102
- # Extract the text of a Rack response as a string.
103
- # Useful for extensions implemented as Rack middleware.
104
- # @param response The response from #call
105
- # @return [String] The whole response as a string.
106
- def self.extract_response_text(response)
107
- # The rack spec states all response bodies must respond to each
108
- result = ''
109
- response.each do |part, s|
110
- result << part
125
+ if path.directory?
126
+ all_files_under(*path.children)
127
+ elsif path.file?
128
+ path
129
+ end
130
+ end.compact
111
131
  end
112
- result
113
- end
114
132
 
115
- # Takes a matcher, which can be a literal string
116
- # or a string containing glob expressions, or a
117
- # regexp, or a proc, or anything else that responds
118
- # to #match or #call, and returns whether or not the
119
- # given path matches that matcher.
120
- #
121
- # @param matcher A matcher string/regexp/proc/etc
122
- # @param path A path as a string
123
- # @return [Boolean] Whether the path matches the matcher
124
- def self.path_match(matcher, path)
125
- if matcher.is_a? String
126
- path.match matcher
127
- elsif matcher.respond_to? :match
128
- matcher.match path
129
- elsif matcher.respond_to? :call
130
- matcher.call path
131
- else
132
- File.fnmatch(matcher.to_s, path)
133
+ # Given a source path (referenced either absolutely or relatively)
134
+ # or a Resource, this will produce the nice URL configured for that
135
+ # path, respecting :relative_links, directory indexes, etc.
136
+ def url_for(app, path_or_resource, options={})
137
+ # Handle Resources and other things which define their own url method
138
+ url = if path_or_resource.respond_to?(:url)
139
+ path_or_resource.url
140
+ else
141
+ path_or_resource.dup
142
+ end.gsub(' ', '%20')
143
+
144
+ # Try to parse URL
145
+ begin
146
+ uri = URI(url)
147
+ rescue URI::InvalidURIError
148
+ # Nothing we can do with it, it's not really a URI
149
+ return url
150
+ end
151
+
152
+ relative = options[:relative]
153
+ raise "Can't use the relative option with an external URL" if relative && uri.host
154
+
155
+ # Allow people to turn on relative paths for all links with
156
+ # set :relative_links, true
157
+ # but still override on a case by case basis with the :relative parameter.
158
+ effective_relative = relative || false
159
+ effective_relative = true if relative.nil? && app.config[:relative_links]
160
+
161
+ # Try to find a sitemap resource corresponding to the desired path
162
+ this_resource = options[:current_resource]
163
+
164
+ if path_or_resource.is_a?(::Middleman::Sitemap::Resource)
165
+ resource = path_or_resource
166
+ resource_url = url
167
+ elsif this_resource && uri.path
168
+ # Handle relative urls
169
+ url_path = Pathname(uri.path)
170
+ current_source_dir = Pathname('/' + this_resource.path).dirname
171
+ url_path = current_source_dir.join(url_path) if url_path.relative?
172
+ resource = app.sitemap.find_resource_by_path(url_path.to_s)
173
+ resource_url = resource.url if resource
174
+ elsif options[:find_resource] && uri.path
175
+ resource = app.sitemap.find_resource_by_path(uri.path)
176
+ resource_url = resource.url if resource
177
+ end
178
+
179
+ if resource
180
+ uri.path = relative_path_from_resource(this_resource, resource_url, effective_relative)
181
+ else
182
+ # If they explicitly asked for relative links but we can't find a resource...
183
+ raise "No resource exists at #{url}" if relative
184
+ end
185
+
186
+ # Support a :query option that can be a string or hash
187
+ if query = options[:query]
188
+ uri.query = query.respond_to?(:to_param) ? query.to_param : query.to_s
189
+ end
190
+
191
+ # Support a :fragment or :anchor option just like Padrino
192
+ fragment = options[:anchor] || options[:fragment]
193
+ uri.fragment = fragment.to_s if fragment
194
+
195
+ # Finally make the URL back into a string
196
+ uri.to_s
133
197
  end
134
- end
135
198
 
136
- # Get a recusive list of files inside a set of paths.
137
- # Works with symlinks.
138
- #
139
- # @param paths Some paths string or Pathname
140
- # @return [Array] An array of filenames
141
- def self.all_files_under(*paths)
142
- paths.flat_map do |p|
143
- path = Pathname(p)
144
- if path.directory?
145
- all_files_under(*path.children)
146
- elsif path.file?
147
- path
199
+ # Expand a path to include the index file if it's a directory
200
+ #
201
+ # @param [String] path Request path/
202
+ # @param [Middleman::Application] app The requesting app.
203
+ # @return [String] Path with index file if necessary.
204
+ def full_path(path, app)
205
+ resource = app.sitemap.find_resource_by_destination_path(path)
206
+
207
+ if !resource
208
+ # Try it with /index.html at the end
209
+ indexed_path = File.join(path.sub(%r{/$}, ''), app.config[:index_file])
210
+ resource = app.sitemap.find_resource_by_destination_path(indexed_path)
148
211
  end
149
- end.compact
150
- end
151
212
 
152
- # Given a source path (referenced either absolutely or relatively)
153
- # or a Resource, this will produce the nice URL configured for that
154
- # path, respecting :relative_links, directory indexes, etc.
155
- def self.url_for(app, path_or_resource, options={})
156
- # Handle Resources and other things which define their own url method
157
- url = path_or_resource.respond_to?(:url) ? path_or_resource.url : path_or_resource
158
- url = url.gsub(' ', '%20')
159
-
160
- begin
161
- uri = URI(url)
162
- rescue URI::InvalidURIError
163
- # Nothing we can do with it, it's not really a URI
164
- return url
213
+ if resource
214
+ '/' + resource.destination_path
215
+ else
216
+ '/' + normalize_path(path)
217
+ end
165
218
  end
166
219
 
167
- relative = options.delete(:relative)
168
- raise "Can't use the relative option with an external URL" if relative && uri.host
169
-
170
- # Allow people to turn on relative paths for all links with
171
- # set :relative_links, true
172
- # but still override on a case by case basis with the :relative parameter.
173
- effective_relative = relative || false
174
- effective_relative = true if relative.nil? && app.config[:relative_links]
175
-
176
- # Try to find a sitemap resource corresponding to the desired path
177
- this_resource = app.current_resource # store in a local var to save work
178
-
179
- if path_or_resource.is_a?(::Middleman::Sitemap::Resource)
180
- resource = path_or_resource
181
- resource_url = url
182
- elsif this_resource && uri.path
183
- # Handle relative urls
184
- url_path = Pathname(uri.path)
185
- current_source_dir = Pathname('/' + this_resource.path).dirname
186
- url_path = current_source_dir.join(url_path) if url_path.relative?
187
- resource = app.sitemap.find_resource_by_path(url_path.to_s)
188
- resource_url = resource.url if resource
189
- elsif options[:find_resource] && uri.path
190
- resource = app.sitemap.find_resource_by_path(uri.path)
191
- resource_url = resource.url if resource
220
+ private
221
+
222
+ # Is mime type known to be non-binary?
223
+ #
224
+ # @param [String] mime The mimetype to check.
225
+ # @return [Boolean]
226
+ def nonbinary_mime?(mime)
227
+ case
228
+ when mime.start_with?('text/')
229
+ true
230
+ when mime.include?('xml')
231
+ true
232
+ when mime.include?('json')
233
+ true
234
+ when mime.include?('javascript')
235
+ true
236
+ else
237
+ false
238
+ end
192
239
  end
193
240
 
194
- if resource
195
- # Switch to the relative path between this_resource and the given resource
241
+ # Read a few bytes from the file and see if they are binary.
242
+ #
243
+ # @param [String] filename The file to check.
244
+ # @return [Boolean]
245
+ def file_contents_include_binary_bytes?(filename)
246
+ binary_bytes = [0, 1, 2, 3, 4, 5, 6, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31]
247
+ s = File.read(filename, 4096) || ''
248
+ s.each_byte do |c|
249
+ return true if binary_bytes.include?(c)
250
+ end
251
+
252
+ false
253
+ end
254
+
255
+ # Get a relative path to a resource.
256
+ #
257
+ # @param [Middleman::Sitemap::Resource] curr_resource The resource.
258
+ # @param [String] resource_url The target url.
259
+ # @param [Boolean] relative If the path should be relative.
260
+ # @return [String]
261
+ def relative_path_from_resource(curr_resource, resource_url, relative)
262
+ # Switch to the relative path between resource and the given resource
196
263
  # if we've been asked to.
197
- if effective_relative
264
+ if relative && curr_resource
198
265
  # Output urls relative to the destination path, not the source path
199
- current_dir = Pathname('/' + this_resource.destination_path).dirname
266
+ current_dir = Pathname('/' + curr_resource.destination_path).dirname
200
267
  relative_path = Pathname(resource_url).relative_path_from(current_dir).to_s
201
268
 
202
269
  # Put back the trailing slash to avoid unnecessary Apache redirects
@@ -204,26 +271,11 @@ module Middleman
204
271
  relative_path << '/'
205
272
  end
206
273
 
207
- uri.path = relative_path
274
+ relative_path
208
275
  else
209
- uri.path = resource_url
276
+ resource_url
210
277
  end
211
- else
212
- # If they explicitly asked for relative links but we can't find a resource...
213
- raise "No resource exists at #{url}" if relative
214
278
  end
215
-
216
- # Support a :query option that can be a string or hash
217
- if query = options.delete(:query)
218
- uri.query = query.respond_to?(:to_param) ? query.to_param : query.to_s
219
- end
220
-
221
- # Support a :fragment or :anchor option just like Padrino
222
- fragment = options.delete(:anchor) || options.delete(:fragment)
223
- uri.fragment = fragment.to_s if fragment
224
-
225
- # Finally make the URL back into a string
226
- uri.to_s
227
279
  end
228
280
  end
229
- end
281
+ end