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
- .url_for(app, path_or_resource, options = {}) ⇒ Object
Methods included from Contracts
Class Method Details
.all_files_under(path, &ignore) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/middleman-core/util/files.rb', line 15 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 |
# 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 result = if resource = app.sitemap.find_resource_by_destination_path(url_for(app, 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
82 83 84 85 86 87 88 89 90 |
# File 'lib/middleman-core/util/files.rb', line 82 def collect_extensions(path) return [] if ::File.basename(path).start_with?('.') result = [] step_through_extensions(path) { |e| result << e } result end |
.current_directory ⇒ Array<String>
Get the PWD and try to keep path encoding consistent.
47 48 49 50 51 52 53 |
# File 'lib/middleman-core/util/files.rb', line 47 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
99 100 101 102 103 104 105 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 |
# File 'lib/middleman-core/util/files.rb', line 99 def (app, files) return [] if files.empty? all_extensions = files.flat_map { |f| collect_extensions(f.to_s) } sass_type_aliasing = ['.scss', '.sass'] erb_type_aliasing = ['.erb', '.haml', '.slim'] if (all_extensions & sass_type_aliasing).length > 0 all_extensions |= sass_type_aliasing end if (all_extensions & erb_type_aliasing).length > 0 all_extensions |= erb_type_aliasing end all_extensions.uniq! app.sitemap.resources.select(&:file_descriptor).select { |r| local_extensions = collect_extensions(r.file_descriptor[:full_path].to_s) if (local_extensions & sass_type_aliasing).length > 0 local_extensions |= sass_type_aliasing end if (local_extensions & erb_type_aliasing).length > 0 local_extensions |= erb_type_aliasing end local_extensions.uniq! ((all_extensions & local_extensions).length > 0) && files.none? { |f| f == r.file_descriptor[:full_path] } }.map(&:file_descriptor) end |
.full_path(path, app) ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/middleman-core/util/paths.rb', line 182 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.
35 36 37 38 39 40 41 |
# File 'lib/middleman-core/util/files.rb', line 35 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
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/middleman-core/util/paths.rb', line 234 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.
233 |
# File 'lib/middleman-core/util/paths.rb', line 233 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 ::Hashie::Mash.new(obj) else obj end end |
.relative_path_from_resource(curr_resource, resource_url, relative) ⇒ Object
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/middleman-core/util/paths.rb', line 205 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
74 75 76 |
# File 'lib/middleman-core/util/files.rb', line 74 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*)([^\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
56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/middleman-core/util/files.rb', line 56 def step_through_extensions(path) while ::Tilt[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
181 |
# File 'lib/middleman-core/util/paths.rb', line 181 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 |
.url_for(app, path_or_resource, options = {}) ⇒ Object
103 104 105 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 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 |
# File 'lib/middleman-core/util/paths.rb', line 103 def url_for(app, path_or_resource, ={}) # 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 |