fakefs 2.6.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 765257209fdbaff32e467e7e5f0acbd9d324d6066fe569d5722a0568368a3288
4
- data.tar.gz: fe4e318738464fd61e4b4d150a06285ea1a1923c92fc51bf244f27afa31b30a2
3
+ metadata.gz: 5e3224ff5a1d920e4564617bcb22fa5a7ece1e956cd8d4ea5602f3486780ac2f
4
+ data.tar.gz: 66ee5d6658990778978ed1531c115ae28ad08414cf9aa1bc90f6fd7e6400b22f
5
5
  SHA512:
6
- metadata.gz: 0b2d56c157243b4a95961f35c946697b229358af469692e91e72ac82eec1c0bdb6b97da19215335f26dd0837b731701bf9d072cb41fbb069f14868f7768d66fc
7
- data.tar.gz: 46b48334206cd89958b8f3177f0e4050580a7c84891f8027e0e768cdfcc8685c22b5cadf03e0bdccb4ae4b9f7bbf788623be644377c53e6ab9277955b8472d9f
6
+ metadata.gz: 42daab712ce7b73ca3ffef7b383834eac7e624bdbf43e4098000fdca7d16cc92d505a5631e256248734962d8db7cb148842d4efc1853686f9cbe5d8b288c6c89
7
+ data.tar.gz: 5514fc676ba615bd6387ad44cc3fa447fc566e265178729d8bb30a4098834e11a9f562f6cc8f25cc88b2c9d386827cc67506b46226008241510c67edbbeb6f81
data/lib/fakefs/base.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RealFile = File
2
4
  RealFileTest = FileTest
3
5
  RealFileUtils = FileUtils
data/lib/fakefs/dir.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'English'
2
4
 
3
5
  module FakeFS
@@ -127,10 +129,10 @@ module FakeFS
127
129
  end
128
130
  end
129
131
 
130
- def self.glob(pattern, _flags = 0, flags: _flags, base: nil, &block) # rubocop:disable Lint/UnderscorePrefixedVariableName
132
+ def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true, &block) # rubocop:disable Lint/UnderscorePrefixedVariableName
131
133
  pwd = FileSystem.normalize_path(base || Dir.pwd)
132
134
  matches_for_pattern = lambda do |matcher|
133
- [FileSystem.find_with_glob(matcher, flags, true, dir: pwd) || []].flatten.map do |e|
135
+ matched = [FileSystem.find_with_glob(matcher, flags, true, dir: pwd) || []].flatten.map do |e|
134
136
  pwd_regex = %r{\A#{pwd.gsub('+') { '\+' }}/?}
135
137
  if pwd.match(%r{\A/?\z}) ||
136
138
  !e.to_s.match(pwd_regex)
@@ -138,7 +140,9 @@ module FakeFS
138
140
  else
139
141
  e.to_s.match(pwd_regex).post_match
140
142
  end
141
- end.sort
143
+ end
144
+ matched.sort! if sort
145
+ matched
142
146
  end
143
147
 
144
148
  files =
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # Fake Dir class
3
5
  class FakeDir
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # Fake file class
3
5
  class FakeFile
4
- attr_accessor :name, :parent, :mtime, :atime, :mode, :uid, :gid
5
- attr_reader :ctime, :birthtime
6
+ attr_accessor :name, :parent, :mtime, :atime, :mode, :uid, :gid, :ctime, :birthtime, :inode
6
7
 
7
8
  def initialize(name = nil, parent = nil)
8
9
  @name = name
@@ -17,8 +18,6 @@ module FakeFS
17
18
  @gid = Process.gid
18
19
  end
19
20
 
20
- attr_accessor :inode
21
-
22
21
  def content
23
22
  @inode.content
24
23
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # Inode class
3
5
  class FakeInode
@@ -10,14 +12,11 @@ module FakeFS
10
12
  assign_inode_num
11
13
  end
12
14
 
13
- attr_accessor :content
14
- attr_accessor :links
15
- attr_accessor :inode_num
15
+ attr_accessor :content, :links, :inode_num
16
16
 
17
17
  # please see: http://iacobson.net/beware-of-ruby-class-variables/
18
18
  class << self
19
- attr_accessor :freed_inodes
20
- attr_accessor :next_inode_num
19
+ attr_accessor :freed_inodes, :next_inode_num
21
20
 
22
21
  # This method should only be used for tests
23
22
  # When called, it will reset the current inode information of the FakeFS
@@ -28,8 +27,7 @@ module FakeFS
28
27
  end
29
28
 
30
29
  def assign_inode_num
31
- if (@inode_num = self.class.freed_inodes.shift)
32
- else
30
+ unless (@inode_num = self.class.freed_inodes.shift)
33
31
  @inode_num = self.class.next_inode_num
34
32
  self.class.next_inode_num += 1
35
33
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # Fake symlink class
3
5
  class FakeSymlink
@@ -29,7 +31,7 @@ module FakeFS
29
31
 
30
32
  private
31
33
 
32
- def method_missing(*args, &block) # rubocop:disable Style/MethodMissingSuper
34
+ def method_missing(*args, &block)
33
35
  entry.send(*args, &block)
34
36
  end
35
37
  end
data/lib/fakefs/file.rb CHANGED
@@ -1,19 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'stringio'
2
4
 
3
5
  module FakeFS
4
6
  # FakeFS File class inherit StringIO
5
7
  class File < StringIO
6
8
  MODES = [
7
- READ_ONLY = 'r'.freeze,
8
- READ_WRITE = 'r+'.freeze,
9
- WRITE_ONLY = 'w'.freeze,
10
- READ_WRITE_TRUNCATE = 'w+'.freeze,
11
- APPEND_WRITE_ONLY = 'a'.freeze,
12
- APPEND_READ_WRITE = 'a+'.freeze
9
+ READ_ONLY = 'r',
10
+ READ_WRITE = 'r+',
11
+ WRITE_ONLY = 'w',
12
+ READ_WRITE_TRUNCATE = 'w+',
13
+ APPEND_WRITE_ONLY = 'a',
14
+ APPEND_READ_WRITE = 'a+'
13
15
  ].freeze
14
16
 
17
+ FMODE_READABLE = 0x00000001
18
+ FMODE_WRITABLE = 0x00000002
19
+ FMODE_READWRITE = (FMODE_READABLE | FMODE_WRITABLE)
20
+ FMODE_BINMODE = 0x00000004
21
+ FMODE_APPEND = 0x00000040
22
+ FMODE_CREATE = 0x00000080
23
+ FMODE_EXCL = 0x00000400
24
+ FMODE_TRUNC = 0x00000800
25
+ FMODE_TEXTMODE = 0x00001000
26
+
27
+ TEXT_MODES = {
28
+ 'r' => FMODE_READABLE,
29
+ 'w' => FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE,
30
+ 'a' => FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE
31
+ }.freeze
32
+
15
33
  FILE_CREATION_MODES = (MODES - [READ_ONLY, READ_WRITE]).freeze
34
+ FILE_ACCESS_MODE = (RealFile::RDONLY | RealFile::WRONLY | RealFile::RDWR)
16
35
 
36
+ # copied from https://github.com/ruby/ruby/blob/v2_7_8/include/ruby/io.h#L108
17
37
  MODE_BITMASK = (
18
38
  RealFile::RDONLY |
19
39
  RealFile::WRONLY |
@@ -23,12 +43,11 @@ module FakeFS
23
43
  RealFile::EXCL |
24
44
  RealFile::NONBLOCK |
25
45
  RealFile::TRUNC |
46
+ RealFile::BINARY |
26
47
  (RealFile.const_defined?(:NOCTTY) ? RealFile::NOCTTY : 0) |
27
48
  (RealFile.const_defined?(:SYNC) ? RealFile::SYNC : 0)
28
49
  )
29
50
 
30
- FILE_CREATION_BITMASK = RealFile::CREAT
31
-
32
51
  def self.extname(path)
33
52
  RealFile.extname(path)
34
53
  end
@@ -181,6 +200,7 @@ module FakeFS
181
200
  symlink.target
182
201
  end
183
202
 
203
+ # TODO: support open_key_args
184
204
  def self.read(path, *args)
185
205
  options = args[-1].is_a?(Hash) ? args.pop : {}
186
206
  length = args.empty? ? nil : args.shift
@@ -259,7 +279,7 @@ module FakeFS
259
279
 
260
280
  def self.delete(*files)
261
281
  files.each do |file|
262
- file_name = (file.class == FakeFS::File ? file.path : file.to_s)
282
+ file_name = (file.instance_of?(FakeFS::File) ? file.path : file.to_s)
263
283
  raise Errno::ENOENT, file_name unless exist?(file_name)
264
284
 
265
285
  FileUtils.rm(file_name)
@@ -344,8 +364,7 @@ module FakeFS
344
364
 
345
365
  # FakeFS Stat class
346
366
  class Stat
347
- attr_reader :ctime, :mtime, :atime, :mode, :uid, :gid
348
- attr_reader :birthtime
367
+ attr_reader :ctime, :mtime, :atime, :mode, :uid, :gid, :birthtime
349
368
 
350
369
  def initialize(file, lstat = false)
351
370
  raise(Errno::ENOENT, file.to_s) unless File.exist?(file)
@@ -490,17 +509,104 @@ module FakeFS
490
509
 
491
510
  attr_reader :path
492
511
 
493
- def initialize(path, mode = READ_ONLY, _perm = nil)
512
+ def initialize(path, *args)
513
+ # unable to pass args otherwise on jruby, it may cause false passes on MRI, though
514
+ # because explicit hash isn't supported
515
+ opts = args.last.is_a?(Hash) ? args.pop : {}
516
+ if args.size > 2
517
+ raise ArgumentError, "wrong number of arguments (given #{args.size + 1}, expected 1..3)"
518
+ end
519
+ mode, _perm = args
520
+
494
521
  @path = path
495
- @mode = mode.is_a?(Hash) ? (mode[:mode] || READ_ONLY) : mode
496
- @file = FileSystem.find(path)
497
- @autoclose = true
522
+ @file = FileSystem.find(@path)
523
+ # real rb_scan_open_args - and rb_io_extract_modeenc - is much more complex
524
+ raise ArgumentError, 'mode specified twice' unless mode.nil? || opts[:mode].nil?
525
+
526
+ mode_opt = mode.nil? ? opts[:mode] : mode
527
+ # see vmode_handle
528
+ if mode_opt.nil?
529
+ @oflags = RealFile::RDONLY
530
+ elsif mode_opt.respond_to?(:to_int) && (intmode = mode_opt.to_int).instance_of?(Integer)
531
+ @oflags = intmode
532
+ else
533
+ unless mode_opt.is_a?(String)
534
+ unless mode_opt.respond_to?(:to_str)
535
+ raise TypeError, "no implicit conversion of #{mode_opt.class} into String"
536
+ end
537
+
538
+ strmode = mode_opt.to_str
539
+ unless strmode.is_a?(String)
540
+ raise TypeError, "can't convert #{mode_opt.class} to String " \
541
+ "(#{mode_opt.class}#to_str gives #{strmode.class})"
542
+ end
498
543
 
499
- check_modes!
544
+ mode_opt = strmode
545
+ end
546
+
547
+ @oflags, @fmode = parse_strmode_oflags(mode_opt)
548
+ end
549
+ unless opts[:flags].nil?
550
+ if opts[:flags].is_a?(Integer)
551
+ @oflags |= opts[:flags]
552
+ elsif opts[:flags].respond_to?(:to_int)
553
+ intflags = opts[:flags].to_int
554
+ unless intflags.instance_of?(Integer)
555
+ raise TypeError, "can't convert #{opts[:flags].class} to Integer " \
556
+ "(#{opts[:flags].class}#to_int gives #{intflags.class})"
557
+ end
500
558
 
559
+ @oflags |= intflags
560
+ @fmode = create_fmode(@oflags)
561
+ else
562
+ raise TypeError, "no implicit conversion of #{opts[:flags].class} into Integer"
563
+ end
564
+ end
565
+ @fmode ||= create_fmode(@oflags)
566
+ @fmode = extract_binmode(opts, @fmode)
567
+
568
+ @autoclose = true
501
569
  file_creation_mode? ? create_missing_file : check_file_existence!
570
+ # StringIO changes enciding of the underlying string to binary
571
+ # when binary data is written if it's opened in binary mode,
572
+ # so content might have binary encoding. StringIO also switches to
573
+ # binary mode if its string have binary encoding, but it might not
574
+ # be what we want, so insteed we use encoding parsed after super call
575
+ # and force set it back.
576
+
577
+ # truncate doesn't work
578
+ unless @file.is_a?(FakeFS::FakeDir)
579
+ @file.content = @file.content.dup.force_encoding(Encoding.default_external)
580
+ end
581
+ # StringIO.new 'content', nil, **{} # works in MRI, but fails in JRuby
582
+ # but File.open 'filename', nil, **{} is ok both in MRI and JRuby
583
+
584
+ # JRuby StringIO doesn't support kwargs without mode
585
+ # StringIO.new "buff", encoding: 'binary' # work on MRI, fails on JRuby
586
+ if RUBY_PLATFORM == "java"
587
+ # other opts aren't supported
588
+ super(@file.content, mode_opt || 'r')
589
+ binmode if binmode? # Looks like it doesn't care about 'b'
590
+ mode_opt_str = mode_opt.is_a?(String) ? mode_opt : ''
591
+ raise ArgumentError, 'encoding specified twice' if mode_opt_str[':'] && opts[:encoding]
592
+
593
+ # Might raise where real File just warns
594
+ str_encoding = mode_opt_str.split(':')[1] # internal encoding is ignored anyway
595
+ if opts[:encoding]
596
+ set_encoding(opts[:encoding])
597
+ elsif str_encoding && str_encoding != ''
598
+ set_encoding(str_encoding)
599
+ elsif opts[:binmode]
600
+ set_encoding(Encoding::BINARY)
601
+ end
602
+ else
603
+ super(@file.content, mode, **opts)
604
+ end
502
605
 
503
- super(@file.content, @mode)
606
+ # StringIO is wrtable and readable by default, so we need to disable it
607
+ # but maybe it was explicitly disabled by opts
608
+ close_write if @fmode & FMODE_WRITABLE == 0 && !StringIO.instance_method(:closed_write?).bind(self).call
609
+ close_read if @fmode & FMODE_READABLE == 0 && !StringIO.instance_method(:closed_read?).bind(self).call
504
610
  end
505
611
 
506
612
  def exists?
@@ -622,10 +728,8 @@ module FakeFS
622
728
  end
623
729
 
624
730
  def binmode?
625
- @mode.is_a?(String) && (
626
- @mode.include?('b') ||
627
- @mode.include?('binary')
628
- ) && !@mode.include?('bom')
731
+ # File.open('test_mode', mode: 'w:binary').binmode? # => false
732
+ @fmode & FMODE_BINMODE != 0
629
733
  end
630
734
 
631
735
  def close_on_exec=(_bool)
@@ -662,31 +766,34 @@ module FakeFS
662
766
 
663
767
  def advise(_advice, _offset = 0, _len = 0); end
664
768
 
665
- def self.write(filename, contents, offset = nil, open_args = {})
666
- offset, open_args = nil, offset if offset.is_a?(Hash)
769
+ def self.write(filename, contents, offset = nil, **open_args)
667
770
  mode = offset ? 'r+' : 'w'
668
- if open_args.any?
669
- if open_args[:open_args]
670
- args = [filename, *open_args[:open_args]]
771
+ if open_args[:open_args]
772
+ # see open_key_args
773
+ # todo: foreach, readlines, read also use it
774
+ # Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
775
+ open_args = open_args[:open_args]
776
+ if open_args.last.is_a?(Hash)
777
+ args = open_args[0...-1]
778
+ opt = open_args.last
671
779
  else
672
- mode = open_args[:mode] || mode
673
- args = [filename, mode, open_args]
780
+ args = open_args
781
+ opt = {}
674
782
  end
675
783
  else
676
- args = [filename, mode]
784
+ args = [open_args.delete(:mode) || mode]
785
+ opt = open_args
677
786
  end
678
787
  if offset
679
- open(*args) do |f| # rubocop:disable Security/Open
788
+ open(filename, *args, **opt) do |f| # rubocop:disable Security/Open
680
789
  f.seek(offset)
681
790
  f.write(contents)
682
791
  end
683
792
  else
684
- open(*args) do |f| # rubocop:disable Security/Open
685
- f << contents
793
+ open(filename, *args, **opt) do |f| # rubocop:disable Security/Open
794
+ f.write(contents)
686
795
  end
687
796
  end
688
-
689
- contents.length
690
797
  end
691
798
 
692
799
  def self.birthtime(path)
@@ -701,16 +808,6 @@ module FakeFS
701
808
  self.class.birthtime(@path)
702
809
  end
703
810
 
704
- def read(length = nil, buf = '')
705
- read_buf = super(length, buf)
706
- if binmode?
707
- read_buf&.force_encoding('ASCII-8BIT')
708
- else
709
- read_buf&.force_encoding(Encoding.default_external)
710
- end
711
- read_buf
712
- end
713
-
714
811
  def self.convert_symbolic_chmod_to_absolute(new_mode, current_mode)
715
812
  # mode always must be of form <GROUP1>=<FLAGS>,<GROUP2>=<FLAGS,...
716
813
  # e.g.: u=wr,go=x
@@ -812,9 +909,9 @@ module FakeFS
812
909
  # note we multiply by 7 since the group num is 1, and octal represents digits 1-7 and we want all 3 bits
813
910
  current_group_mode = current_file_mode & (group_num * 7)
814
911
  if group_num == 0o100
815
- current_group_mode = current_group_mode >> 6
912
+ current_group_mode >>= 6
816
913
  elsif group_num == 0o10
817
- current_group_mode = current_group_mode >> 3
914
+ current_group_mode >>= 3
818
915
  end
819
916
 
820
917
  current_group_mode
@@ -832,7 +929,7 @@ module FakeFS
832
929
  elsif assignment_mode == '-'
833
930
  current_group_mode & ~chmod_perm_num
834
931
  else
835
- raise ArguementError "Unknown assignment mode #{assignment_mode}"
932
+ raise ArgumentError, "Unknown assignment mode #{assignment_mode}"
836
933
  end
837
934
  end
838
935
 
@@ -866,8 +963,95 @@ module FakeFS
866
963
 
867
964
  private
868
965
 
869
- def check_modes!
870
- StringIO.new('', @mode)
966
+ def extract_binmode(opts, fmode)
967
+ textmode = opts[:textmode]
968
+ unless textmode.nil?
969
+ raise ArgumentError, "textmode specified twice" if fmode & FMODE_TEXTMODE != 0
970
+ raise ArgumentError, "both textmode and binmode specified" if fmode & FMODE_BINMODE != 0
971
+
972
+ # yep, false has no effect here, but still causes ArgumentError
973
+ fmode |= FMODE_TEXTMODE if textmode
974
+ end
975
+
976
+ binmode = opts[:binmode]
977
+ unless binmode.nil?
978
+ raise ArgumentError, "binmode specified twice" if fmode & FMODE_BINMODE != 0
979
+ raise ArgumentError, "both textmode and binmode specified" if fmode & FMODE_TEXTMODE != 0
980
+
981
+ fmode |= FMODE_BINMODE if binmode
982
+ end
983
+
984
+ if fmode & FMODE_BINMODE != 0 && fmode & FMODE_TEXTMODE != 0
985
+ raise ArgumentError, "both textmode and binmode specified"
986
+ end
987
+
988
+ fmode
989
+ end
990
+
991
+ def create_fmode(oflags)
992
+ # rb_io_oflags_fmode
993
+ fmode = 0
994
+ case oflags & FILE_ACCESS_MODE
995
+ when RealFile::RDONLY
996
+ fmode = FMODE_READABLE
997
+ when RealFile::WRONLY
998
+ fmode = FMODE_WRITABLE
999
+ when RealFile::RDWR
1000
+ fmode = FMODE_READWRITE
1001
+ end
1002
+ fmode |= FMODE_APPEND if (oflags & RealFile::APPEND) != 0
1003
+ fmode |= FMODE_TRUNC if (oflags & RealFile::TRUNC) != 0
1004
+ fmode |= FMODE_CREATE if (oflags & RealFile::CREAT) != 0
1005
+ fmode |= FMODE_EXCL if (oflags & RealFile::EXCL) != 0
1006
+ fmode |= FMODE_BINMODE if (oflags & RealFile::BINARY) != 0
1007
+ fmode
1008
+ end
1009
+
1010
+ def parse_strmode_oflags(mode)
1011
+ # rb_io_modestr_fmode
1012
+ access_mode = mode[0]
1013
+ mode_modificators = mode[1..-1].split(':', 2).first
1014
+ fmode = TEXT_MODES[access_mode]
1015
+ raise ArgumentError, "invalid access mode #{mode}" unless fmode
1016
+
1017
+ mode_modificators&.each_char do |m|
1018
+ case m
1019
+ when 'b'
1020
+ fmode |= FMODE_BINMODE
1021
+ when 't'
1022
+ fmode |= FMODE_TEXTMODE
1023
+ when '+'
1024
+ fmode |= FMODE_READWRITE
1025
+ when 'x'
1026
+ raise ArgumentError, "invalid access mode #{mode}" unless access_mode == 'w'
1027
+
1028
+ fmode |= FMODE_EXCL
1029
+ else
1030
+ raise ArgumentError, "invalid access mode #{mode}"
1031
+ end
1032
+ end
1033
+ if (fmode & FMODE_BINMODE).nonzero? && (fmode & FMODE_TEXTMODE).nonzero?
1034
+ raise ArgumentError, "invalid access mode #{mode}"
1035
+ end
1036
+
1037
+ # rb_io_fmode_oflags
1038
+ oflags = 0
1039
+ case fmode & FMODE_READWRITE
1040
+ when FMODE_READABLE
1041
+ oflags |= RealFile::RDONLY
1042
+ when FMODE_WRITABLE
1043
+ oflags |= RealFile::WRONLY
1044
+ when FMODE_READWRITE
1045
+ oflags |= RealFile::RDWR
1046
+ end
1047
+
1048
+ oflags |= RealFile::APPEND if (fmode & FMODE_APPEND).nonzero?
1049
+ oflags |= RealFile::TRUNC if (fmode & FMODE_TRUNC).nonzero?
1050
+ oflags |= RealFile::CREAT if (fmode & FMODE_CREATE).nonzero?
1051
+ oflags |= RealFile::EXCL if (fmode & FMODE_EXCL).nonzero?
1052
+ oflags |= RealFile::BINARY if (fmode & FMODE_BINMODE).nonzero?
1053
+
1054
+ [oflags, fmode]
871
1055
  end
872
1056
 
873
1057
  def check_file_existence!
@@ -875,27 +1059,21 @@ module FakeFS
875
1059
  end
876
1060
 
877
1061
  def file_creation_mode?
878
- mode_in?(FILE_CREATION_MODES) || mode_in_bitmask?(FILE_CREATION_BITMASK)
1062
+ mode_in?(RealFile::CREAT)
879
1063
  end
880
1064
 
881
- def mode_in?(list)
882
- if @mode.respond_to?(:include?)
883
- list.any? do |element|
884
- @mode.include?(element)
885
- end
886
- end
887
- end
888
-
889
- def mode_in_bitmask?(mask)
890
- (@mode & mask) != 0 if @mode.is_a?(Integer)
1065
+ def mode_in?(mask)
1066
+ (@oflags & mask) != 0
891
1067
  end
892
1068
 
893
1069
  # Create a missing file if the path is valid.
894
1070
  #
895
1071
  def create_missing_file
896
- raise Errno::EISDIR, path.to_s if File.directory?(@path)
897
-
898
- return if File.exist?(@path) # Unnecessary check, probably.
1072
+ if @file
1073
+ raise Errno::EEXIST, @path.to_s if mode_in?(RealFile::EXCL)
1074
+ raise Errno::EISDIR, path.to_s if File.directory?(@path)
1075
+ return
1076
+ end
899
1077
  dirname = RealFile.dirname @path
900
1078
 
901
1079
  unless dirname == '.'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # FileSystem module
3
5
  module FileSystem
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # FileTest
3
5
  module FileTest
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # FileUtils module
3
5
  module FileUtils
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'file'
2
4
 
3
5
  module FakeFS
@@ -27,18 +29,22 @@ module FakeFS
27
29
  int_mode = mode.to_int
28
30
 
29
31
  unless int_mode.is_a?(Integer)
30
- raise TypeError, "can't convert Object to Integer (#{mode.class}#to_int gives #{int_mode.class})"
32
+ raise TypeError, "can't convert #{mode.class} to Integer (#{mode.class}#to_int gives #{int_mode.class})"
31
33
  end
32
34
  mode = int_mode
33
35
  end
34
36
 
35
- # real implementation may not fail on `flock 11111` - but fails with `f1.flock 11111111` - or may fail
36
- # with another error - `f1.flock 1111111111111` gives `integer 1111111111111 too big to convert to `int'
37
- # but I think it's safer to allow only documented modes.
37
+ # In fact, real implementation may not fail on `flock 11111` -
38
+ # - but fails with `f1.flock 11111111` - or may fail
39
+ # with another error - `f1.flock 1111111111111` gives
40
+ # `integer 1111111111111 too big to convert to `int' (RangeError)`
41
+ # - but I think it's safer to allow only documented modes.
38
42
  unless FAKE_FS_ALLOWED_FLOCK_MODES.include?(mode)
39
43
  # real exception
40
44
  # Invalid argument @ rb_file_flock - filepath (Errno::EINVAL)
41
- raise Errno::EINVAL.new(@path, 'rb_file_flock')
45
+ # raise Errno::EINVAL.new(@path, 'rb_file_flock')
46
+ # represents it better, but fails on JRuby
47
+ raise Errno::EINVAL, @path
42
48
  end
43
49
  0
44
50
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # Handles globbing for FakeFS.
3
5
  module Globber
@@ -8,14 +10,14 @@ module FakeFS
8
10
 
9
11
  return [pattern] if pattern[0] != '{' || pattern[-1] != '}'
10
12
 
11
- part = ''
13
+ part = +''
12
14
  result = []
13
15
 
14
16
  each_char_with_levels pattern, '{', '}' do |chr, level|
15
17
  case level
16
18
  when 0
17
19
  case chr
18
- when '{' # rubocop:disable Lint/EmptyWhen
20
+ when '{'
19
21
  # noop
20
22
  else
21
23
  part << chr
@@ -24,8 +26,8 @@ module FakeFS
24
26
  case chr
25
27
  when ','
26
28
  result << part
27
- part = ''
28
- when '}' # rubocop:disable Lint/EmptyWhen
29
+ part = +''
30
+ when '}'
29
31
  # noop
30
32
  else
31
33
  part << chr
@@ -43,13 +45,13 @@ module FakeFS
43
45
  def path_components(pattern)
44
46
  pattern = pattern.to_s
45
47
 
46
- part = ''
48
+ part = +''
47
49
  result = []
48
50
 
49
51
  each_char_with_levels pattern, '{', '}' do |chr, level|
50
52
  if level == 0 && chr == File::SEPARATOR
51
53
  result << part
52
- part = ''
54
+ part = +''
53
55
  else
54
56
  part << chr
55
57
  end
data/lib/fakefs/io.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # FakeFS IO class inherit root IO
3
5
  # Only minimal mocks are provided as IO may be used by ruby's internals
data/lib/fakefs/irb.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'irb'
2
4
 
3
5
  # Make the original file system classes available in IRB.
data/lib/fakefs/kernel.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # Kernel Module
3
5
  module Kernel
@@ -16,7 +18,7 @@ module FakeFS
16
18
  end
17
19
 
18
20
  def self.unhijack!
19
- captives[:original].each do |name, _prc|
21
+ captives[:original].each_key do |name|
20
22
  ::Kernel.send(:remove_method, name.to_sym)
21
23
  ::Kernel.send(:define_method, name.to_sym, proc do |*args, **kwargs, &block|
22
24
  ::FakeFS::Kernel.captives[:original][name].call(*args, **kwargs, &block)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # FakeFS module
2
4
  module FakeFS
3
5
  #
@@ -109,10 +111,10 @@ module FakeFS
109
111
  if File::ALT_SEPARATOR
110
112
  SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}" \
111
113
  "#{Regexp.quote File::SEPARATOR}".freeze
112
- SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/.freeze
114
+ SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
113
115
  else
114
116
  SEPARATOR_LIST = (Regexp.quote File::SEPARATOR).to_s.freeze
115
- SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/.freeze
117
+ SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
116
118
  end
117
119
 
118
120
  # Return a pathname which the extension of the basename is substituted by
@@ -483,7 +485,8 @@ module FakeFS
483
485
  while (r = chop_basename(pre))
484
486
  pre, base = r
485
487
  case base
486
- when '.' # rubocop:disable Lint/EmptyWhen
488
+ when '.'
489
+ # ignored
487
490
  when '..'
488
491
  names.unshift base
489
492
  else
data/lib/fakefs/pry.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Define Pry class if it's not defined. Useful if pry
2
4
  # is required after loading FakeFS
3
5
  ::Pry = Class.new unless defined?(::Pry)
data/lib/fakefs/safe.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
  require 'pathname'
3
5
  require 'fakefs/pry'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # FakeFS::SpecHelpers provides a simple macro for RSpec example
2
4
  # groups to turn FakeFS on and off.
3
5
  # To use it simply require 'fakefs/spec_helpers', then include
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FakeFS
2
4
  # Version module
3
5
  module Version
4
- VERSION = '2.6.0'.freeze
6
+ VERSION = '3.0.0'
5
7
 
6
8
  def self.to_s
7
9
  VERSION
data/lib/fakefs.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fakefs/safe'
2
4
 
3
5
  FakeFS.activate!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fakefs
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Wanstrath
@@ -9,39 +9,66 @@ authors:
9
9
  - Jeff Hodges
10
10
  - Pat Nakajima
11
11
  - Brian Donovan
12
- autorequire:
13
12
  bindir: bin
14
13
  cert_chain: []
15
- date: 2024-12-08 00:00:00.000000000 Z
14
+ date: 2025-01-20 00:00:00.000000000 Z
16
15
  dependencies:
17
16
  - !ruby/object:Gem::Dependency
18
17
  name: bump
19
18
  requirement: !ruby/object:Gem::Requirement
20
19
  requirements:
21
- - - "~>"
20
+ - - ">="
22
21
  - !ruby/object:Gem::Version
23
- version: 0.5.3
22
+ version: '0'
24
23
  type: :development
25
24
  prerelease: false
26
25
  version_requirements: !ruby/object:Gem::Requirement
27
26
  requirements:
28
- - - "~>"
27
+ - - ">="
29
28
  - !ruby/object:Gem::Version
30
- version: 0.5.3
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: csv
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
31
44
  - !ruby/object:Gem::Dependency
32
45
  name: maxitest
33
46
  requirement: !ruby/object:Gem::Requirement
34
47
  requirements:
35
- - - "~>"
48
+ - - ">="
36
49
  - !ruby/object:Gem::Version
37
- version: '3.6'
50
+ version: '0'
38
51
  type: :development
39
52
  prerelease: false
40
53
  version_requirements: !ruby/object:Gem::Requirement
41
54
  requirements:
42
- - - "~>"
55
+ - - ">="
43
56
  - !ruby/object:Gem::Version
44
- version: '3.6'
57
+ version: '0'
58
+ - !ruby/object:Gem::Dependency
59
+ name: mutex_m
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
45
72
  - !ruby/object:Gem::Dependency
46
73
  name: pry
47
74
  requirement: !ruby/object:Gem::Requirement
@@ -62,42 +89,42 @@ dependencies:
62
89
  requirements:
63
90
  - - ">="
64
91
  - !ruby/object:Gem::Version
65
- version: '10.3'
92
+ version: '0'
66
93
  type: :development
67
94
  prerelease: false
68
95
  version_requirements: !ruby/object:Gem::Requirement
69
96
  requirements:
70
97
  - - ">="
71
98
  - !ruby/object:Gem::Version
72
- version: '10.3'
99
+ version: '0'
73
100
  - !ruby/object:Gem::Dependency
74
101
  name: rspec
75
102
  requirement: !ruby/object:Gem::Requirement
76
103
  requirements:
77
- - - "~>"
104
+ - - ">="
78
105
  - !ruby/object:Gem::Version
79
- version: '3.1'
106
+ version: '0'
80
107
  type: :development
81
108
  prerelease: false
82
109
  version_requirements: !ruby/object:Gem::Requirement
83
110
  requirements:
84
- - - "~>"
111
+ - - ">="
85
112
  - !ruby/object:Gem::Version
86
- version: '3.1'
113
+ version: '0'
87
114
  - !ruby/object:Gem::Dependency
88
115
  name: rubocop
89
116
  requirement: !ruby/object:Gem::Requirement
90
117
  requirements:
91
118
  - - "~>"
92
119
  - !ruby/object:Gem::Version
93
- version: 0.82.0
120
+ version: 1.70.0
94
121
  type: :development
95
122
  prerelease: false
96
123
  version_requirements: !ruby/object:Gem::Requirement
97
124
  requirements:
98
125
  - - "~>"
99
126
  - !ruby/object:Gem::Version
100
- version: 0.82.0
127
+ version: 1.70.0
101
128
  description: A fake filesystem. Use it in your tests.
102
129
  email:
103
130
  - chris@ozmm.org
@@ -132,7 +159,6 @@ homepage: https://github.com/fakefs/fakefs
132
159
  licenses:
133
160
  - MIT
134
161
  metadata: {}
135
- post_install_message:
136
162
  rdoc_options: []
137
163
  require_paths:
138
164
  - lib
@@ -140,15 +166,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
140
166
  requirements:
141
167
  - - ">="
142
168
  - !ruby/object:Gem::Version
143
- version: 2.7.0
169
+ version: 3.0.0
144
170
  required_rubygems_version: !ruby/object:Gem::Requirement
145
171
  requirements:
146
172
  - - ">="
147
173
  - !ruby/object:Gem::Version
148
174
  version: '0'
149
175
  requirements: []
150
- rubygems_version: 3.5.11
151
- signing_key:
176
+ rubygems_version: 3.6.2
152
177
  specification_version: 4
153
178
  summary: A fake filesystem. Use it in your tests.
154
179
  test_files: []