Module: Sprockets::PathUtils

Extended by:
PathUtils
Included in:
Base, Loader, PathDependencyUtils, PathDigestUtils, PathUtils, Paths
Defined in:
lib/sprockets/path_utils.rb

Overview

Internal: File and path related utilities. Mixed into Environment.

Probably would be called FileUtils, but that causes namespace annoyances when code actually wants to reference ::FileUtils.

Constant Summary collapse

SEPARATOR_PATTERN =
"#{Regexp.quote(File::SEPARATOR)}"

Instance Method Summary collapse

Instance Method Details

#absolute_path?(path) ⇒ Boolean

On Windows, ALT_SEPARATOR is \ Delegate to Pathname since the logic gets complex.

Returns:

  • (Boolean)


78
79
80
# File 'lib/sprockets/path_utils.rb', line 78

def absolute_path?(path)
  Pathname.new(path).absolute?
end

#atomic_write(filename) ⇒ Object

Public: Write to a file atomically. Useful for situations where you don’t want other processes or threads to see half-written files.

Utils.atomic_write('important.file') do |file|
  file.write('hello')
end

Returns nothing.



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/sprockets/path_utils.rb', line 268

def atomic_write(filename)
  dirname, basename = File.split(filename)
  basename = [
    basename,
    Thread.current.object_id,
    Process.pid,
    rand(1000000)
  ].join('.')
  tmpname = File.join(dirname, basename)

  File.open(tmpname, 'wb+') do |f|
    yield f
  end

  File.rename(tmpname, filename)
ensure
  File.delete(tmpname) if File.exist?(tmpname)
end

#directory?(path) ⇒ Boolean

Public: Like ‘File.directory?`.

path - String file path.

Returns true path exists and is a directory.

Returns:

  • (Boolean)


40
41
42
43
44
45
46
# File 'lib/sprockets/path_utils.rb', line 40

def directory?(path)
  if stat = self.stat(path)
    stat.directory?
  else
    false
  end
end

#entries(path) ⇒ Object

Public: A version of ‘Dir.entries` that filters out `.` files and `~` swap files.

path - String directory path

Returns an empty ‘Array` if the directory does not exist.



54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/sprockets/path_utils.rb', line 54

def entries(path)
  if File.directory?(path)
    entries = Dir.entries(path, :encoding => Encoding.default_internal)
    entries.reject! { |entry|
      entry.start_with?(".".freeze) ||
        (entry.start_with?("#".freeze) && entry.end_with?("#".freeze)) ||
        entry.end_with?("~".freeze)
    }
    entries.sort!
  else
    []
  end
end

#file?(path) ⇒ Boolean

Public: Like ‘File.file?`.

path - String file path.

Returns true path exists and is a file.

Returns:

  • (Boolean)


27
28
29
30
31
32
33
# File 'lib/sprockets/path_utils.rb', line 27

def file?(path)
  if stat = self.stat(path)
    stat.file?
  else
    false
  end
end

#find_upwards(basename, path, root = nil) ⇒ Object

Internal: Find target basename checking upwards from path.

basename - String filename: “.sprocketsrc” path - String path to start search: “app/assets/javascripts/app.js” root - String path to stop at (default: system root)

Returns String filename or nil.



193
194
195
196
197
198
199
# File 'lib/sprockets/path_utils.rb', line 193

def find_upwards(basename, path, root = nil)
  path_parents(path, root).each do |dir|
    filename = File.join(dir, basename)
    return filename if file?(filename)
  end
  nil
end

#match_path_extname(path, extensions) ⇒ Object

Internal: Match path extnames against available extensions.

path - String extensions - Hash of String extnames to values

Returns [String extname, Object value] or nil nothing matched.



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/sprockets/path_utils.rb', line 150

def match_path_extname(path, extensions)
  basename = File.basename(path)

  i = basename.index('.'.freeze)
  while i && i < basename.length - 1
    extname = basename[i..-1]
    if value = extensions[extname]
      return extname, value
    end

    i = basename.index('.'.freeze, i+1)
  end

  nil
end

#path_extnames(path) ⇒ Object

Internal: Get path’s extensions.

path - String

Returns an Array of String extnames.



140
141
142
# File 'lib/sprockets/path_utils.rb', line 140

def path_extnames(path)
  File.basename(path).scan(/\.[^.]+/)
end

#path_parents(path, root = nil) ⇒ Object

Internal: Returns all parents for path

path - String absolute filename or directory root - String path to stop at (default: system root)

Returns an Array of String paths.



172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/sprockets/path_utils.rb', line 172

def path_parents(path, root = nil)
  root = "#{root}#{File::SEPARATOR}" if root
  parents = []

  loop do
    parent = File.dirname(path)
    break if parent == path
    break if root && !path.start_with?(root)
    parents << path = parent
  end

  parents
end

#paths_split(paths, filename) ⇒ Object

Internal: Detect root path and base for file in a set of paths.

paths - Array of String paths filename - String path of file expected to be in one of the paths.

Returns [String root, String path]



126
127
128
129
130
131
132
133
# File 'lib/sprockets/path_utils.rb', line 126

def paths_split(paths, filename)
  paths.each do |path|
    if subpath = split_subpath(path, filename)
      return path, subpath
    end
  end
  nil
end

#relative_path?(path) ⇒ Boolean

Public: Check if path is explicitly relative. Starts with “./” or “../”.

path - String path.

Returns true if path is relative, otherwise false.

Returns:

  • (Boolean)


99
100
101
# File 'lib/sprockets/path_utils.rb', line 99

def relative_path?(path)
  path =~ /^\.\.?($|#{SEPARATOR_PATTERN})/ ? true : false
end

#split_subpath(path, subpath) ⇒ Object

Internal: Get relative path for root path and subpath.

path - String path subpath - String subpath of path

Returns relative String path if subpath is a subpath of path, or nil if subpath is outside of path.



110
111
112
113
114
115
116
117
118
# File 'lib/sprockets/path_utils.rb', line 110

def split_subpath(path, subpath)
  return "" if path == subpath
  path = File.join(path, '')
  if subpath.start_with?(path)
    subpath[path.length..-1]
  else
    nil
  end
end

#stat(path) ⇒ Object

Public: Like ‘File.stat`.

path - String file or directory path

Returns nil if the file does not exist.



14
15
16
17
18
19
20
# File 'lib/sprockets/path_utils.rb', line 14

def stat(path)
  if File.exist?(path)
    File.stat(path.to_s)
  else
    nil
  end
end

#stat_directory(dir) ⇒ Object

Public: Stat all the files under a directory.

dir - A String directory

Returns an Enumerator of [path, stat].



206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/sprockets/path_utils.rb', line 206

def stat_directory(dir)
  return to_enum(__method__, dir) unless block_given?

  self.entries(dir).each do |entry|
    path = File.join(dir, entry)
    if stat = self.stat(path)
      yield path, stat
    end
  end

  nil
end

#stat_sorted_tree(dir, &block) ⇒ Object

Public: Recursive stat all the files under a directory in alphabetical order.

dir - A String directory

Returns an Enumerator of [path, stat].



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/sprockets/path_utils.rb', line 244

def stat_sorted_tree(dir, &block)
  return to_enum(__method__, dir) unless block_given?

  self.stat_directory(dir).sort_by { |path, stat|
    stat.directory? ? "#{path}/" : path
  }.each do |path, stat|
    yield path, stat

    if stat.directory?
      stat_sorted_tree(path, &block)
    end
  end

  nil
end

#stat_tree(dir, &block) ⇒ Object

Public: Recursive stat all the files under a directory.

dir - A String directory

Returns an Enumerator of [path, stat].



224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/sprockets/path_utils.rb', line 224

def stat_tree(dir, &block)
  return to_enum(__method__, dir) unless block_given?

  self.stat_directory(dir) do |path, stat|
    yield path, stat

    if stat.directory?
      stat_tree(path, &block)
    end
  end

  nil
end