class FakeFS::File
Constants
- FILE_CREATION_BITMASK
- FILE_CREATION_MODES
- MODES
- MODE_BITMASK
Attributes
autoclose[RW]
path[R]
Public Class Methods
absolute_path(file_name, dir_name = Dir.getwd)
click to toggle source
# File lib/fakefs/file.rb, line 643 def self.absolute_path(file_name, dir_name = Dir.getwd) RealFile.absolute_path(file_name, dir_name) end
atime(path)
click to toggle source
# File lib/fakefs/file.rb, line 90 def self.atime(path) if exist?(path) FileSystem.find(path).atime else raise Errno::ENOENT end end
basename(*args)
click to toggle source
# File lib/fakefs/file.rb, line 171 def self.basename(*args) RealFile.basename(*args) end
binread(file, length = nil, offset = 0)
click to toggle source
# File lib/fakefs/file.rb, line 328 def self.binread(file, length = nil, offset = 0) File.read(file, length, offset, mode: 'rb:ASCII-8BIT') end
binwrite(file, content, offset = nil)
click to toggle source
# File lib/fakefs/file.rb, line 332 def self.binwrite(file, content, offset = nil) mode = offset ? 'r+b:ASCII-8BIT' : 'wb:ASCII-8BIT' File.write(file, content, offset, mode: mode) end
birthtime(path)
click to toggle source
# File lib/fakefs/file.rb, line 692 def self.birthtime(path) if exist?(path) FileSystem.find(path).birthtime else raise Errno::ENOENT end end
chmod(new_mode, filename)
click to toggle source
# File lib/fakefs/file.rb, line 291 def self.chmod(new_mode, filename) # chmod's mode can either be passed in in absolute mode, or symbolic mode # for reference: https://ruby-doc.org/stdlib-2.2.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-chmod # if the mode is passed in symbolic mode we must convert it to absolute mode is_absolute_mode = new_mode.is_a? Numeric unless is_absolute_mode current_mode = FileSystem.find(filename).mode new_mode = convert_symbolic_chmod_to_absolute(new_mode, current_mode) end FileSystem.find(filename).mode = 0o100000 + new_mode end
chown(owner_int, group_int, filename)
click to toggle source
# File lib/fakefs/file.rb, line 311 def self.chown(owner_int, group_int, filename) file = FileSystem.find(filename) if owner_int && owner_int != -1 owner_int.is_a?(Integer) || raise(TypeError, "can't convert String into Integer") file.uid = owner_int end if group_int && group_int != -1 group_int.is_a?(Integer) || raise(TypeError, "can't convert String into Integer") file.gid = group_int end end
const_missing(name)
click to toggle source
# File lib/fakefs/file.rb, line 133 def self.const_missing(name) RealFile.const_get(name) end
ctime(path)
click to toggle source
# File lib/fakefs/file.rb, line 82 def self.ctime(path) if exist?(path) FileSystem.find(path).ctime else raise Errno::ENOENT end end
delete(*files)
click to toggle source
# File lib/fakefs/file.rb, line 260 def self.delete(*files) files.each do |file| file_name = (file.class == FakeFS::File ? file.path : file.to_s) raise Errno::ENOENT, file_name unless exist?(file_name) FileUtils.rm(file_name) end files.size end
Also aliased as: unlink
directory?(path)
click to toggle source
# File lib/fakefs/file.rb, line 137 def self.directory?(path) if path.respond_to? :entry path.entry.is_a? FakeDir else result = FileSystem.find(path) result ? result.entry.is_a?(FakeDir) : false end end
dirname(*args)
click to toggle source
# File lib/fakefs/file.rb, line 175 def self.dirname(*args) RealFile.dirname(*args) end
executable?(filename)
click to toggle source
Not exactly right, returns true if the file is chmod +x for owner. In the context of when you would use fakefs, this is usually what you want.
# File lib/fakefs/file.rb, line 305 def self.executable?(filename) file = FileSystem.find(filename) return false unless file (file.mode - 0o100000) & 0o100 != 0 end
exist?(path)
click to toggle source
# File lib/fakefs/file.rb, line 44 def self.exist?(path) if File.symlink?(path) referent = File.expand_path(File.readlink(path), File.dirname(path)) exist?(referent) else !FileSystem.find(path).nil? end end
expand_path(file_name, dir_string = FileSystem.current_dir.to_s)
click to toggle source
# File lib/fakefs/file.rb, line 167 def self.expand_path(file_name, dir_string = FileSystem.current_dir.to_s) RealFile.expand_path(file_name, RealFile.expand_path(dir_string, Dir.pwd)) end
extname(path)
click to toggle source
# File lib/fakefs/file.rb, line 32 def self.extname(path) RealFile.extname(path) end
file?(path)
click to toggle source
# File lib/fakefs/file.rb, line 154 def self.file?(path) if path.respond_to? :entry path.entry.is_a? FakeFile else result = FileSystem.find(path) result ? result.entry.is_a?(FakeFile) : false end end
fnmatch?(pattern, path, flags = 0)
click to toggle source
# File lib/fakefs/file.rb, line 337 def self.fnmatch?(pattern, path, flags = 0) RealFile.fnmatch?(pattern, path, flags) end
Also aliased as: fnmatch
foreach(path, *args, &block)
click to toggle source
# File lib/fakefs/file.rb, line 208 def self.foreach(path, *args, &block) file = new(path) if file.exists? FileSystem.find(path).atime = Time.now if block_given? file.each_line(*args, &block) else file.each_line(*args) end else raise Errno::ENOENT end end
ftype(filename)
click to toggle source
# File lib/fakefs/file.rb, line 163 def self.ftype(filename) File.lstat(filename).ftype end
identical?(one_path, another_path)
click to toggle source
# File lib/fakefs/file.rb, line 54 def identical?(one_path, another_path) FileSystem.find(one_path) == FileSystem.find(another_path) end
join(*parts)
click to toggle source
# File lib/fakefs/file.rb, line 36 def self.join(*parts) RealFile.join(parts) end
link(source, dest)
click to toggle source
# File lib/fakefs/file.rb, line 248 def self.link(source, dest) raise Errno::EPERM, "#{source} or #{dest}" if directory?(source) raise Errno::ENOENT, "#{source} or #{dest}" unless exist?(source) raise Errno::EEXIST, "#{source} or #{dest}" if exist?(dest) source = FileSystem.find(source) dest = FileSystem.add(dest, source.entry.clone) source.link(dest) 0 end
lstat(file)
click to toggle source
# File lib/fakefs/file.rb, line 283 def self.lstat(file) File::Stat.new(file, true) end
mtime(path)
click to toggle source
# File lib/fakefs/file.rb, line 74 def self.mtime(path) if exist?(path) FileSystem.find(path).mtime else raise Errno::ENOENT end end
new(path, mode = READ_ONLY, _perm = nil)
click to toggle source
Calls superclass method
# File lib/fakefs/file.rb, line 493 def initialize(path, mode = READ_ONLY, _perm = nil) @path = path @mode = mode.is_a?(Hash) ? (mode[:mode] || READ_ONLY) : mode @file = FileSystem.find(path) @autoclose = true check_modes! file_creation_mode? ? create_missing_file : check_file_existence! super(@file.content, @mode) end
path(file)
click to toggle source
# File lib/fakefs/file.rb, line 40 def self.path(file) RealFile.path(file) end
read(path, *args)
click to toggle source
# File lib/fakefs/file.rb, line 184 def self.read(path, *args) options = args[-1].is_a?(Hash) ? args.pop : {} length = args.empty? ? nil : args.shift offset = args.empty? ? 0 : args.shift file = new(path, **options) raise Errno::ENOENT unless file.exists? raise Errno::EISDIR, path.to_s if directory?(path) FileSystem.find(path).atime = Time.now file.seek(offset) file.read(length) end
readable?(path)
click to toggle source
# File lib/fakefs/file.rb, line 64 def self.readable?(path) return false unless exist? path File.lstat(path).readable? end
readlines(path, chomp: false)
click to toggle source
# File lib/fakefs/file.rb, line 198 def self.readlines(path, chomp: false) file = new(path) if file.exists? FileSystem.find(path).atime = Time.now chomp ? file.readlines.map(&:chomp) : file.readlines else raise Errno::ENOENT end end
readlink(path)
click to toggle source
# File lib/fakefs/file.rb, line 179 def self.readlink(path) symlink = FileSystem.find(path) symlink.target end
realdirpath(*args)
click to toggle source
# File lib/fakefs/file.rb, line 659 def self.realdirpath(*args) RealFile.realdirpath(*args) end
realpath(*args)
click to toggle source
# File lib/fakefs/file.rb, line 620 def self.realpath(*args) RealFile.realpath(*args) end
rename(source, dest)
click to toggle source
# File lib/fakefs/file.rb, line 222 def self.rename(source, dest) if directory?(source) && file?(dest) raise Errno::ENOTDIR, "#{source} or #{dest}" elsif file?(source) && directory?(dest) raise Errno::EISDIR, "#{source} or #{dest}" elsif !exist?(dirname(dest)) raise Errno::ENOENT, "#{source} or #{dest}" end if (target = FileSystem.find(source)) return 0 if source == dest if target.is_a?(FakeFS::FakeSymlink) File.symlink(target.target, dest) else FileSystem.add(dest, target.entry.clone) end FileSystem.delete(source) else raise Errno::ENOENT, "#{source} or #{dest}" end 0 end
size(path)
click to toggle source
# File lib/fakefs/file.rb, line 111 def self.size(path) if directory?(path) 64 + (32 * FileSystem.find(path).entries.size) else read(path).bytesize end end
size?(path)
click to toggle source
# File lib/fakefs/file.rb, line 119 def self.size?(path) size(path) if exist?(path) && !size(path).zero? end
split(path)
click to toggle source
# File lib/fakefs/file.rb, line 287 def self.split(path) RealFile.split(path) end
stat(file)
click to toggle source
# File lib/fakefs/file.rb, line 279 def self.stat(file) File::Stat.new(file) end
sticky?(_path)
click to toggle source
Assume nothing is sticky.
# File lib/fakefs/file.rb, line 59 def sticky?(_path) false end
symlink(source, dest)
click to toggle source
# File lib/fakefs/file.rb, line 275 def self.symlink(source, dest) FileUtils.ln_s(source, dest) end
symlink?(path)
click to toggle source
# File lib/fakefs/file.rb, line 146 def self.symlink?(path) if path.respond_to? :entry path.is_a? FakeSymlink else FileSystem.find(path).is_a? FakeSymlink end end
umask(*args)
click to toggle source
# File lib/fakefs/file.rb, line 324 def self.umask(*args) RealFile.umask(*args) end
utime(atime, mtime, *paths)
click to toggle source
# File lib/fakefs/file.rb, line 98 def self.utime(atime, mtime, *paths) paths.each do |path| if exist?(path) FileSystem.find(path).atime = atime FileSystem.find(path).mtime = mtime else raise Errno::ENOENT end end paths.size end
writable?(path)
click to toggle source
# File lib/fakefs/file.rb, line 69 def self.writable?(path) return false unless exist? path File.lstat(path).writable? end
write(filename, contents, offset = nil, open_args = {})
click to toggle source
# File lib/fakefs/file.rb, line 665 def self.write(filename, contents, offset = nil, open_args = {}) offset, open_args = nil, offset if offset.is_a?(Hash) mode = offset ? 'r+' : 'w' if open_args.any? if open_args[:open_args] args = [filename, *open_args[:open_args]] else mode = open_args[:mode] || mode args = [filename, mode, open_args] end else args = [filename, mode] end if offset open(*args) do |f| # rubocop:disable Security/Open f.seek(offset) f.write(contents) end else open(*args) do |f| # rubocop:disable Security/Open f << contents end end contents.length end
zero?(path)
click to toggle source
# File lib/fakefs/file.rb, line 123 def self.zero?(path) exist?(path) && size(path) == 0 end
Also aliased as: empty?
Private Class Methods
calculate_chmod_amt_for_mode(modes)
click to toggle source
given a list of modes [rwx] (a) ensure all modes are valid and (b) return the numeric value associated with the modes
# File lib/fakefs/file.rb, line 841 def self.calculate_chmod_amt_for_mode(modes) valid_modes_to_numeric_vals = { 'r' => 0o4, 'w' => 0o2, 'x' => 0o1 } # if we give no modes, then we are removing all permission chmod_perm_num = 0o0 if modes != '' # make sure there are no invalid flags in the modes and that we discard duplicates as chmod does given_modes = modes.split('') given_modes = given_modes.uniq given_modes.each do |specific_mode| # ensure that the mode is valid unless valid_modes_to_numeric_vals.key? specific_mode raise ArgumentError, "Invalid `perm' symbol in file mode: #{specific_mode}" end chmod_perm_num += valid_modes_to_numeric_vals[specific_mode] end end chmod_perm_num end
convert_symbolic_chmod_to_absolute(new_mode, current_mode)
click to toggle source
# File lib/fakefs/file.rb, line 714 def self.convert_symbolic_chmod_to_absolute(new_mode, current_mode) # mode always must be of form <GROUP1>=<FLAGS>,<GROUP2>=<FLAGS,... # e.g.: u=wr,go=x chmod_pairs = new_mode.split(',') # - duplicating groups is OK ( e.g.: 'ugouuoouu' is valid and is interpretted as 'ugo' ) # - duplicating modes is OK ( e.g.: 'wwwwwwwww' is interpreted as 'w' ) # - omitting the right hand side is interpretted as removing all permission # ( e.g.: 'ugo=' is really 'chmod 000' ) # - omitting the left hand side is interpretted as all groups ( e.g.: '=rwx' is really 'ugo=rwx' ) # - if we list a group more than once, we only apply the rightmost permissions # ( e.g.: 'ug=rx,g=x' is really 'u=r,g=x' ) # - we cannot list any flags that are not 'rwx' ( e.g.: converting 'ug=rwx' to 'ug=7' is invalid ) # or else an error is raised # - in the example above, the following error is raised: 'invalid `perm' symbol in file mode: 7 (ArgumentError)' # - we cannot put in any groups that are not 'ugo' ( e.g.: listing groups as 'uzg=x' is invalid ) # or else an error is raised # - in the example above, the following error is raised: 'invalid `who' symbol in file mode: z (ArgumentError)' valid_groups_to_numeric_vals = { 'u' => 0o100, 'g' => 0o10, 'o' => 0o1 } # make sure we preload the current group values. # chmod works by calculating new permissions based off of existing permissions current_groups_to_vals = { 0o100 => 0o0, 0o10 => 0o0, 0o1 => 0o0 } [0o100, 0o10, 0o1].each do |group_num| perm_amt = get_perms_for_group(current_mode, group_num) current_groups_to_vals[group_num] = perm_amt end chmod_pairs.each do |pair| # see if we are dealing with +/- ( granting or removing permissions ) or = ( assigning permissions ) # note that it IS valid to mix assignment and granting/revoking perissions ( things like u=wrx,g+x are valid ) assign_perms = '=' remove_perms = '-' add_perms = '+' assignment_mode = nil if pair.include? remove_perms assignment_mode = remove_perms elsif pair.include? add_perms assignment_mode = add_perms elsif pair.include? assign_perms assignment_mode = assign_perms end # if we can't find a mode, then raise an exception as real `chmod` would if assignment_mode.nil? raise ArgumentError, "Invalid file mode: #{mode}" end adding_removing_perms = [add_perms, remove_perms].include?(assignment_mode) groups = pair.rpartition(assignment_mode).first modes = pair.rpartition(assignment_mode).last # get the numeric chmod value associated with the symbolic entry chmod_perm_num = calculate_chmod_amt_for_mode modes # if we give no groups, then we are giving all groups if groups == '' if adding_removing_perms [0o100, 0o10, 0o1].each do |group_num| perm_amt = set_perms_for_group(current_groups_to_vals, group_num, assignment_mode, chmod_perm_num) current_groups_to_vals[group_num] = perm_amt end else [0o100, 0o10, 0o1].each do |group_num| current_groups_to_vals[group_num] = chmod_perm_num end end else # make sure there are no invalid flags in the groups and that we discard duplicates as chmod does given_groups = groups.split('') given_groups = given_groups.uniq given_groups.each do |specific_group| # ensure that the group is valid unless valid_groups_to_numeric_vals.key? specific_group raise ArgumentError, "Invalid `who' symbol in file mode: #{specific_group}" end # take the current chmod amt from earlier and associate that as the current chmod factor for the group # if we are adding or removing groups ( via +/- ) then we must make sure that we adjust # the current chmod perm number for the group group_num = valid_groups_to_numeric_vals[specific_group] adjusted_chmod = chmod_perm_num if adding_removing_perms adjusted_chmod = set_perms_for_group(current_groups_to_vals, group_num, assignment_mode, chmod_perm_num) end current_groups_to_vals[group_num] = adjusted_chmod end end end # return an octal chmod value for the value 0o100 * current_groups_to_vals[0o100] + 0o10 * current_groups_to_vals[0o10] + current_groups_to_vals[0o1] end
get_perms_for_group(current_file_mode, group_num)
click to toggle source
return the group mode for group num based off the provided current_file_mode
# File lib/fakefs/file.rb, line 809 def self.get_perms_for_group(current_file_mode, group_num) # get the current recorded mode of the group and return it to the caller # note we don't shift for 'o' since that is the bottom 3 bits # note we multiply by 7 since the group num is 1, and octal represents digits 1-7 and we want all 3 bits current_group_mode = current_file_mode & (group_num * 7) if group_num == 0o100 current_group_mode = current_group_mode >> 6 elsif group_num == 0o10 current_group_mode = current_group_mode >> 3 end current_group_mode end
set_perms_for_group(current_groups_to_vals, group_num, assignment_mode, chmod_perm_num)
click to toggle source
given the current chmod values for a file return the result of adding or removing chmod_perm_num from the requested groups permissions ( so performing <GROUP>+<PERMS> or <GROUP>-<PERMS>
# File lib/fakefs/file.rb, line 825 def self.set_perms_for_group(current_groups_to_vals, group_num, assignment_mode, chmod_perm_num) # get the current recorded mode of the group current_group_mode = current_groups_to_vals[group_num] # now that we have the current value of the group, add or remove bits accordingly if assignment_mode == '+' current_group_mode | chmod_perm_num elsif assignment_mode == '-' current_group_mode & ~chmod_perm_num else raise ArguementError "Unknown assignment mode #{assignment_mode}" end end
Public Instance Methods
advise(_advice, _offset = 0, _len = 0)
click to toggle source
# File lib/fakefs/file.rb, line 663 def advise(_advice, _offset = 0, _len = 0); end
atime()
click to toggle source
# File lib/fakefs/file.rb, line 578 def atime self.class.atime(@path) end
autoclose?()
click to toggle source
# File lib/fakefs/file.rb, line 649 def autoclose? @autoclose ? true : false end
binmode?()
click to toggle source
# File lib/fakefs/file.rb, line 624 def binmode? @mode.is_a?(String) && ( @mode.include?('b') || @mode.include?('binary') ) && !@mode.include?('bom') end
birthtime()
click to toggle source
# File lib/fakefs/file.rb, line 700 def birthtime self.class.birthtime(@path) end
chmod(new_mode)
click to toggle source
# File lib/fakefs/file.rb, line 594 def chmod(new_mode) # chmod's mode can either be passed in in absolute mode, or symbolic mode # for reference: https://ruby-doc.org/stdlib-2.2.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-chmod # if the mode is passed in symbolic mode we must convert it to absolute mode is_absolute_mode = new_mode.is_a? Numeric unless is_absolute_mode current_mode = @file.mode new_mode = convert_symbolic_chmod_to_absolute(new_mode, current_mode) end @file.mode = 0o100000 + new_mode end
chown(owner_int, group_int)
click to toggle source
# File lib/fakefs/file.rb, line 606 def chown(owner_int, group_int) return unless group_int && group_int != -1 owner_int.is_a?(Integer) || raise( TypeError, "can't convert String into Integer" ) @file.uid = owner_int group_int.is_a?(Integer) || raise( TypeError, "can't convert String into Integer" ) @file.gid = group_int end
close_on_exec=(_bool)
click to toggle source
# File lib/fakefs/file.rb, line 631 def close_on_exec=(_bool) raise NotImplementedError end
close_on_exec?()
click to toggle source
# File lib/fakefs/file.rb, line 635 def close_on_exec? raise NotImplementedError end
ctime()
click to toggle source
# File lib/fakefs/file.rb, line 582 def ctime self.class.ctime(@path) end
exists?()
click to toggle source
# File lib/fakefs/file.rb, line 506 def exists? true end
flock(*)
click to toggle source
# File lib/fakefs/file.rb, line 586 def flock(*) raise NotImplementedError end
ioctl(*)
click to toggle source
# File lib/fakefs/file.rb, line 543 def ioctl(*) raise NotImplementedError end
is_a?(klass)
click to toggle source
# File lib/fakefs/file.rb, line 535 def is_a?(klass) RealFile.allocate.is_a?(klass) end
lstat()
click to toggle source
# File lib/fakefs/file.rb, line 555 def lstat self.class.lstat(@path) end
mtime()
click to toggle source
# File lib/fakefs/file.rb, line 590 def mtime self.class.mtime(@path) end
read(length = nil, buf = '')
click to toggle source
Calls superclass method
# File lib/fakefs/file.rb, line 704 def read(length = nil, buf = '') read_buf = super(length, buf) if binmode? read_buf&.force_encoding('ASCII-8BIT') else read_buf&.force_encoding(Encoding.default_external) end read_buf end
Also aliased as: sysread
read_nonblock()
click to toggle source
# File lib/fakefs/file.rb, line 547 def read_nonblock raise NotImplementedError end
readpartial(*)
click to toggle source
Calls superclass method
# File lib/fakefs/file.rb, line 574 def readpartial(*) super end
size()
click to toggle source
# File lib/fakefs/file.rb, line 655 def size File.size(@path) end
stat()
click to toggle source
# File lib/fakefs/file.rb, line 551 def stat self.class.stat(@path) end
string()
click to toggle source
# File lib/fakefs/file.rb, line 539 def string gets(nil) end
sysseek(position, whence = SEEK_SET)
click to toggle source
# File lib/fakefs/file.rb, line 559 def sysseek(position, whence = SEEK_SET) seek(position, whence) pos end
to_io()
click to toggle source
# File lib/fakefs/file.rb, line 566 def to_io self end
to_path()
click to toggle source
# File lib/fakefs/file.rb, line 639 def to_path @path end
write(*args)
click to toggle source
Calls superclass method
# File lib/fakefs/file.rb, line 510 def write(*args) val = super(*args) @file.mtime = Time.now val end
Also aliased as: syswrite
write_nonblock(*)
click to toggle source
# File lib/fakefs/file.rb, line 570 def write_nonblock(*) raise NotImplementedError end
Private Instance Methods
check_file_existence!()
click to toggle source
# File lib/fakefs/file.rb, line 873 def check_file_existence! raise Errno::ENOENT, @path.to_s unless @file end
check_modes!()
click to toggle source
split the private class method decleration so rubocop doesn’t complain the line is too long
# File lib/fakefs/file.rb, line 869 def check_modes! StringIO.new('', @mode) end
create_missing_file()
click to toggle source
Create a missing file if the path is valid.
# File lib/fakefs/file.rb, line 895 def create_missing_file raise Errno::EISDIR, path.to_s if File.directory?(@path) return if File.exist?(@path) # Unnecessary check, probably. dirname = RealFile.dirname @path unless dirname == '.' dir = FileSystem.find dirname raise Errno::ENOENT, path.to_s unless dir.is_a? FakeDir end @file = FileSystem.add(path, FakeFile.new) end
file_creation_mode?()
click to toggle source
# File lib/fakefs/file.rb, line 877 def file_creation_mode? mode_in?(FILE_CREATION_MODES) || mode_in_bitmask?(FILE_CREATION_BITMASK) end
mode_in?(list)
click to toggle source
# File lib/fakefs/file.rb, line 881 def mode_in?(list) if @mode.respond_to?(:include?) list.any? do |element| @mode.include?(element) end end end
mode_in_bitmask?(mask)
click to toggle source
# File lib/fakefs/file.rb, line 889 def mode_in_bitmask?(mask) (@mode & mask) != 0 if @mode.is_a?(Integer) end