Module: Middleman::Util
- 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
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
- .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, &_block) ⇒ Object
- .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_recognizes?(path) ⇒ Boolean
- .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
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/paths.rb', line 38 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
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/middleman-core/util/paths.rb', line 69 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 = 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_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 = ::URI.encode(relative_path_from_resource([:current_resource], result, [:relative])) result_uri = 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
90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/middleman-core/util/files.rb', line 90 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
69 70 71 72 73 74 75 76 77 |
# File 'lib/middleman-core/util/binary.rb', line 69 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
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 |
# File 'lib/middleman-core/util/files.rb', line 112 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
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/middleman-core/util/paths.rb', line 191 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
19 20 21 22 |
# File 'lib/middleman-core/util.rb', line 19 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 62 |
# File 'lib/middleman-core/util/binary.rb', line 49 def nonbinary_mime?(mime) case when mime.start_with?('text/') true when mime.include?('xml') && !mime.include?('officedocument') true when mime.include?('json') true when mime.include?('javascript') true else false end end |
.normalize_path(path) ⇒ Object
18 19 20 21 |
# File 'lib/middleman-core/util/paths.rb', line 18 def normalize_path(path) # The tr call works around a bug in Ruby's Unicode handling ::URI.decode(path).sub(%r{^/}, '').tr('', '') end |
.path_match(matcher, path) ⇒ Object
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/middleman-core/util/paths.rb', line 243 def path_match(matcher, path) case when matcher.is_a?(String) if matcher.include? '*' ::File.fnmatch(matcher, path) else path == matcher end when matcher.respond_to?(:match) !!(path =~ matcher) when 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.
242 |
# File 'lib/middleman-core/util/paths.rb', line 242 Contract PATH_MATCHER, String => Bool |
.recursively_enhance(obj) ⇒ Object
28 29 30 31 32 33 34 35 36 |
# File 'lib/middleman-core/util/data.rb', line 28 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
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/middleman-core/util/paths.rb', line 214 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
82 83 84 |
# File 'lib/middleman-core/util/files.rb', line 82 def remove_templating_extensions(path) step_through_extensions(path) end |
.rewrite_paths(body, _path, exts, &_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 |
# File 'lib/middleman-core/util/rack.rb', line 24 def rewrite_paths(body, _path, exts, &_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 begin uri = ::Addressable::URI.parse(asset_path) if uri.relative? && uri.host.nil? && !(asset_path =~ /^[^\/].*[a-z]+\.[a-z]+\/.*/) && (result = yield(asset_path)) "#{opening_character}#{result}" else match end rescue ::Addressable::URI::InvalidURIError match end end end |
.step_through_extensions(path) {|::File.extname(path)| ... } ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/middleman-core/util/files.rb', line 64 def step_through_extensions(path) while tilt_recognizes?(path) ext = ::File.extname(path) 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
190 |
# File 'lib/middleman-core/util/paths.rb', line 190 Contract String, ::Middleman::Application => String |
.strip_leading_slash(path) ⇒ Object
26 27 28 |
# File 'lib/middleman-core/util/paths.rb', line 26 def strip_leading_slash(path) path.sub(%r{^/}, '') end |
.tilt_recognizes?(path) ⇒ Boolean
58 59 60 61 |
# File 'lib/middleman-core/util/files.rb', line 58 def tilt_recognizes?(path) @@tilt_lookup_cache ||= {} @@tilt_lookup_cache[path] ||= ::Tilt[path] end |
.url_for(app, path_or_resource, options = {}) ⇒ Object
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 147 148 149 150 151 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 |
# File 'lib/middleman-core/util/paths.rb', line 107 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 if r 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 = URI(url) rescue ::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 ::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 |