middleman-core 3.2.1 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.
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