Module: Middleman::Util
- Extended by:
- Memoist
- Includes:
- Contracts
- Defined in:
- lib/middleman-core/util.rb,
lib/middleman-core/util/data.rb,
lib/middleman-core/util/rack.rb,
lib/middleman-core/util/files.rb,
lib/middleman-core/util/paths.rb,
lib/middleman-core/util/binary.rb,
lib/middleman-core/util/uri_templates.rb
Defined Under Namespace
Modules: Data, UriTemplates Classes: BlogTemplateProcessor, EnhancedHash
Constant Summary collapse
Constants included from Contracts
Class Method Summary collapse
- .all_files_under(path, &ignore) ⇒ Object
- .asset_path(app, kind, source, options = {}) ⇒ Object
- .asset_url(app, path, prefix = '', options = {}) ⇒ Object
- .binary?(filename) ⇒ Boolean
- .collect_extensions(path) ⇒ Object
-
.current_directory ⇒ Array<String>
Get the PWD and try to keep path encoding consistent.
-
.each ⇒ String
Extract the text of a Rack response as a string.
- .extract_response_text(response) ⇒ Object
- .file_contents_include_binary_bytes?(filename) ⇒ Boolean
- .find_related_files(app, files) ⇒ Object
- .full_path(path, app) ⇒ Object
-
.glob_directory(path) ⇒ Array<String>
Glob a directory and try to keep path encoding consistent.
-
.instrument(name, payload = {}, &block) ⇒ Object
Facade for ActiveSupport/Notification.
- .nonbinary_mime?(mime) ⇒ Boolean
- .normalize_path(path) ⇒ Object
- .parse_uri(uri) ⇒ Object
- .path_match(matcher, path) ⇒ Object
-
.PATH_MATCHER ⇒ Boolean
Takes a matcher, which can be a literal string or a string containing glob expressions, or a regexp, or a proc, or anything else that responds to #match or #call, and returns whether or not the given path matches that matcher.
- .recursively_enhance(obj) ⇒ Object
- .relative_path_from_resource(curr_resource, resource_url, relative) ⇒ Object
- .remove_templating_extensions(path) ⇒ Object
- .rewrite_paths(body, path, exts, app, &_block) ⇒ Object
- .should_ignore?(validator, value) ⇒ Boolean
- .step_through_extensions(path) {|::File.extname(path)| ... } ⇒ Object
-
.String ⇒ String
Expand a path to include the index file if it's a directory.
- .strip_leading_slash(path) ⇒ Object
- .tilt_class(path) ⇒ Object
- .url_for(app, path_or_resource, options = {}) ⇒ Object
Methods included from Contracts
Class Method Details
.all_files_under(path, &ignore) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/middleman-core/util/files.rb', line 17 def all_files_under(path, &ignore) path = Pathname(path) if ignore && yield(path) [] elsif path.directory? path.children.flat_map do |child| all_files_under(child, &ignore) end.compact elsif path.file? [path] else [] end end |
.asset_path(app, kind, source, options = {}) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/middleman-core/util/paths.rb', line 75 def asset_path(app, kind, source, ={}) return source if source.to_s.include?('//') || source.to_s.start_with?('data:') asset_folder = case kind when :css app.config[:css_dir] when :js app.config[:js_dir] when :images app.config[:images_dir] when :fonts app.config[:fonts_dir] else kind.to_s end source = source.to_s.tr(' ', '') ignore_extension = (kind == :images || kind == :fonts) # don't append extension source << ".#{kind}" unless ignore_extension || source.end_with?(".#{kind}") asset_folder = '' if source.start_with?('/') # absolute path asset_url(app, source, asset_folder, ) end |
.asset_url(app, path, prefix = '', options = {}) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/middleman-core/util/paths.rb', line 106 def asset_url(app, path, prefix='', ={}) # Don't touch assets which already have a full path return path if path.include?('//') || path.start_with?('data:') if [:relative] && ![:current_resource] raise ArgumentError, '#asset_url must be run in a context with current_resource if relative: true' end uri = ::Middleman::Util.parse_uri(path) path = uri.path # Ensure the url we pass into find_resource_by_destination_path is not a # relative path, since it only takes absolute url paths. dest_path = url_for(app, path, .merge(relative: false)) result = if resource = app.sitemap.find_resource_by_path(dest_path) resource.url elsif resource = app.sitemap.find_resource_by_destination_path(dest_path) resource.url else path = ::File.join(prefix, path) if resource = app.sitemap.find_resource_by_path(path) resource.url else ::File.join(app.config[:http_prefix], path) end end final_result = ::Addressable::URI.encode( relative_path_from_resource( [:current_resource], result, [:relative] ) ) result_uri = ::Middleman::Util.parse_uri(final_result) result_uri.query = uri.query result_uri.fragment = uri.fragment result_uri.to_s end |
.binary?(filename) ⇒ Boolean
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/middleman-core/util/binary.rb', line 18 def binary?(filename) @binary_cache ||= {} return @binary_cache[filename] if @binary_cache.key?(filename) @binary_cache[filename] = begin path = Pathname(filename) ext = path.extname # We hardcode detecting of gzipped SVG files if ext == '.svgz' true elsif ::Tilt.registered?(ext.sub('.', '')) false else dot_ext = ext.to_s[0] == '.' ? ext.dup : ".#{ext}" if mime = ::Rack::Mime.mime_type(dot_ext, nil) !nonbinary_mime?(mime) else file_contents_include_binary_bytes?(path.to_s) end end end end |
.collect_extensions(path) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/middleman-core/util/files.rb', line 86 def collect_extensions(path) @@extensions_cache ||= {} base_name = ::File.basename(path) @@extensions_cache[base_name] ||= begin result = [] unless base_name.start_with?('.') step_through_extensions(base_name) { |e| result << e } end result end end |
.current_directory ⇒ Array<String>
Get the PWD and try to keep path encoding consistent.
49 50 51 52 53 54 55 |
# File 'lib/middleman-core/util/files.rb', line 49 def current_directory result = ::Dir.pwd return result unless RUBY_PLATFORM =~ /darwin/ result.encode('UTF-8', 'UTF-8-MAC') end |
.each ⇒ String
Extract the text of a Rack response as a string. Useful for extensions implemented as Rack middleware.
13 |
# File 'lib/middleman-core/util/rack.rb', line 13 Contract RespondTo[:each] => String |
.extract_response_text(response) ⇒ Object
14 15 16 17 18 19 20 21 |
# File 'lib/middleman-core/util/rack.rb', line 14 def extract_response_text(response) # The rack spec states all response bodies must respond to each result = '' response.each do |part, _| result << part end result end |
.file_contents_include_binary_bytes?(filename) ⇒ Boolean
68 69 70 71 72 73 74 75 76 |
# File 'lib/middleman-core/util/binary.rb', line 68 def file_contents_include_binary_bytes?(filename) 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] s = ::File.read(filename, 4096) || '' s.each_byte do |c| return true if binary_bytes.include?(c) end false end |
.find_related_files(app, files) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/middleman-core/util/files.rb', line 108 def (app, files) return [] if files.empty? file_set = ::Set.new(files) all_extensions = files.flat_map { |f| collect_extensions(f.to_s) } sass_type_aliasing = ['.scss', '.sass'] erb_type_aliasing = ['.erb', '.haml', '.slim'] all_extensions |= sass_type_aliasing unless (all_extensions & sass_type_aliasing).empty? all_extensions |= erb_type_aliasing unless (all_extensions & erb_type_aliasing).empty? all_extensions.uniq! app.sitemap.resources.select { |r| if r.file_descriptor local_extensions = collect_extensions(r.file_descriptor[:full_path].to_s) local_extensions |= sass_type_aliasing unless (local_extensions & sass_type_aliasing).empty? local_extensions |= erb_type_aliasing unless (local_extensions & erb_type_aliasing).empty? local_extensions.uniq! !(all_extensions & local_extensions).empty? && !file_set.include?(r.file_descriptor[:full_path]) else false end }.map(&:file_descriptor) end |
.full_path(path, app) ⇒ Object
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/middleman-core/util/paths.rb', line 243 def full_path(path, app) resource = app.sitemap.find_resource_by_destination_path(path) unless resource # Try it with /index.html at the end indexed_path = ::File.join(path.sub(%r{/$}, ''), app.config[:index_file]) resource = app.sitemap.find_resource_by_destination_path(indexed_path) end if resource '/' + resource.destination_path else '/' + normalize_path(path) end end |
.glob_directory(path) ⇒ Array<String>
Glob a directory and try to keep path encoding consistent.
37 38 39 40 41 42 43 |
# File 'lib/middleman-core/util/files.rb', line 37 def glob_directory(path) results = ::Dir[path] return results unless RUBY_PLATFORM =~ /darwin/ results.map { |r| r.encode('UTF-8', 'UTF-8-MAC') } end |
.instrument(name, payload = {}, &block) ⇒ Object
Facade for ActiveSupport/Notification
18 19 20 21 |
# File 'lib/middleman-core/util.rb', line 18 def instrument(name, payload={}, &block) suffixed_name = name =~ /\.middleman$/ ? name.dup : "#{name}.middleman" ::ActiveSupport::Notifications.instrument(suffixed_name, payload, &block) end |
.nonbinary_mime?(mime) ⇒ Boolean
49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/middleman-core/util/binary.rb', line 49 def nonbinary_mime?(mime) if mime.start_with?('text/') true elsif mime.include?('xml') && !mime.include?('officedocument') true elsif mime.include?('json') true elsif mime.include?('javascript') true else false end end |
.normalize_path(path) ⇒ Object
34 35 36 37 |
# File 'lib/middleman-core/util/paths.rb', line 34 def normalize_path(path) # The tr call works around a bug in Ruby's Unicode handling Addressable::URI.unencode(path).sub(%r{^/}, '').tr('', '') end |
.parse_uri(uri) ⇒ Object
19 20 21 |
# File 'lib/middleman-core/util/paths.rb', line 19 def parse_uri(uri) ::Addressable::URI.parse(uri) end |
.path_match(matcher, path) ⇒ Object
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/middleman-core/util/paths.rb', line 295 def path_match(matcher, path) if matcher.is_a?(String) if matcher.include? '*' ::File.fnmatch(matcher, path) else path == matcher end elsif matcher.respond_to?(:match) !!(path =~ matcher) elsif matcher.respond_to?(:call) matcher.call(path) else ::File.fnmatch(matcher.to_s, path) end end |
.PATH_MATCHER ⇒ Boolean
Takes a matcher, which can be a literal string or a string containing glob expressions, or a regexp, or a proc, or anything else that responds to #match or #call, and returns whether or not the given path matches that matcher.
294 |
# File 'lib/middleman-core/util/paths.rb', line 294 Contract PATH_MATCHER, String => Bool |
.recursively_enhance(obj) ⇒ Object
30 31 32 33 34 35 36 37 38 |
# File 'lib/middleman-core/util/data.rb', line 30 def recursively_enhance(obj) if obj.is_a? ::Array obj.map { |e| recursively_enhance(e) } elsif obj.is_a? ::Hash EnhancedHash.new(obj) else obj end end |
.relative_path_from_resource(curr_resource, resource_url, relative) ⇒ Object
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/middleman-core/util/paths.rb', line 266 def relative_path_from_resource(curr_resource, resource_url, relative) # Switch to the relative path between resource and the given resource # if we've been asked to. if relative # Output urls relative to the destination path, not the source path current_dir = Pathname('/' + curr_resource.destination_path).dirname relative_path = Pathname(resource_url).relative_path_from(current_dir).to_s # Put back the trailing slash to avoid unnecessary Apache redirects if resource_url.end_with?('/') && !relative_path.end_with?('/') relative_path << '/' end relative_path else resource_url end end |
.remove_templating_extensions(path) ⇒ Object
78 79 80 |
# File 'lib/middleman-core/util/files.rb', line 78 def remove_templating_extensions(path) step_through_extensions(path) end |
.rewrite_paths(body, path, exts, app, &_block) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/middleman-core/util/rack.rb', line 24 def rewrite_paths(body, path, exts, app, &_block) matcher = /([\'\"\(,]\s*|# sourceMappingURL=)([^\s\'\"\)\(>]+(#{::Regexp.union(exts)}))/ url_fn_prefix = 'url(' body.dup.gsub(matcher) do |match| opening_character = $1 asset_path = $2 if asset_path.start_with?(url_fn_prefix) opening_character << url_fn_prefix asset_path = asset_path[url_fn_prefix.length..-1] end current_resource = app.sitemap.find_resource_by_destination_path(path) begin uri = ::Middleman::Util.parse_uri(asset_path) if uri.relative? && uri.host.nil? && !(asset_path =~ /^[^\/].*[a-z]+\.[a-z]+\/.*/) dest_path = ::Middleman::Util.url_for(app, asset_path, relative: false, current_resource: current_resource) resource = app.sitemap.find_resource_by_destination_path(dest_path) if resource && (result = yield(asset_path)) "#{opening_character}#{result}" else match end else match end rescue ::Addressable::URI::InvalidURIError match end end end |
.should_ignore?(validator, value) ⇒ Boolean
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/middleman-core/util/paths.rb', line 50 def should_ignore?(validator, value) if validator.is_a? Regexp # Treat as Regexp !!(value =~ validator) elsif validator.respond_to? :call # Treat as proc validator.call(value) elsif validator.is_a? String # Treat as glob File.fnmatch(value, validator) else # If some unknown thing, don't ignore false end end |
.step_through_extensions(path) {|::File.extname(path)| ... } ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/middleman-core/util/files.rb', line 58 def step_through_extensions(path) while ::Middleman::Util.tilt_class(path) ext = ::File.extname(path) break if ext.empty? yield ext if block_given? # Strip templating extensions as long as Tilt knows them path = path[0..-(ext.length + 1)] end yield ::File.extname(path) if block_given? path end |
.String ⇒ String
Expand a path to include the index file if it's a directory
242 |
# File 'lib/middleman-core/util/paths.rb', line 242 Contract String, ::Middleman::Application => String |
.strip_leading_slash(path) ⇒ Object
43 44 45 |
# File 'lib/middleman-core/util/paths.rb', line 43 def strip_leading_slash(path) path.sub(%r{^/}, '') end |
.tilt_class(path) ⇒ Object
25 26 27 |
# File 'lib/middleman-core/util/paths.rb', line 25 def tilt_class(path) ::Tilt[path] end |
.url_for(app, path_or_resource, options = {}) ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/middleman-core/util/paths.rb', line 152 def url_for(app, path_or_resource, ={}) if path_or_resource.is_a?(String) || path_or_resource.is_a?(Symbol) r = app.sitemap.find_resource_by_page_id(path_or_resource) path_or_resource = r ? r : path_or_resource.to_s end # Handle Resources and other things which define their own url method url = if path_or_resource.respond_to?(:url) path_or_resource.url else path_or_resource.dup end # Try to parse URL begin uri = ::Middleman::Util.parse_uri(url) rescue ::Addressable::URI::InvalidURIError # Nothing we can do with it, it's not really a URI return url end relative = [:relative] raise "Can't use the relative option with an external URL" if relative && uri.host # Allow people to turn on relative paths for all links with # set :relative_links, true # but still override on a case by case basis with the :relative parameter. effective_relative = relative || false effective_relative = true if relative.nil? && app.config[:relative_links] # Try to find a sitemap resource corresponding to the desired path this_resource = [:current_resource] if path_or_resource.is_a?(::Middleman::Sitemap::Resource) resource = path_or_resource resource_url = url elsif this_resource && uri.path && !uri.host # Handle relative urls url_path = Pathname(uri.path) current_source_dir = Pathname('/' + this_resource.path).dirname url_path = current_source_dir.join(url_path) if url_path.relative? resource = app.sitemap.find_resource_by_path(url_path.to_s) if resource resource_url = resource.url else # Try to find a resource relative to destination paths url_path = Pathname(uri.path) current_source_dir = Pathname('/' + this_resource.destination_path).dirname url_path = current_source_dir.join(url_path) if url_path.relative? resource = app.sitemap.find_resource_by_destination_path(url_path.to_s) resource_url = resource.url if resource end elsif [:find_resource] && uri.path && !uri.host resource = app.sitemap.find_resource_by_path(uri.path) resource_url = resource.url if resource end if resource uri.path = if this_resource ::Addressable::URI.encode( relative_path_from_resource( this_resource, resource_url, effective_relative ) ) else resource_url end end # Support a :query option that can be a string or hash if query = [:query] uri.query = query.respond_to?(:to_param) ? query.to_param : query.to_s end # Support a :fragment or :anchor option just like Padrino fragment = [:anchor] || [:fragment] uri.fragment = fragment.to_s if fragment # Finally make the URL back into a string uri.to_s end |