Class: FunWith::Files::FilePath

Inherits:
Pathname
  • Object
show all
Defined in:
lib/fun_with/files/file_path.rb

Direct Known Subclasses

RemotePath

Constant Summary collapse

SUCC_DIGIT_COUNT =
6

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args, &block) ⇒ FilePath

Returns a new instance of FilePath.



6
7
8
9
# File 'lib/fun_with/files/file_path.rb', line 6

def initialize( *args, &block )
  super( File.join( *(args.map(&:to_s) ) ) )
  _yield_and_return( self, &block )
end

Instance Attribute Details

#pathObject

Returns the value of attribute path.



11
12
13
# File 'lib/fun_with/files/file_path.rb', line 11

def path
  @path
end

Class Method Details

.tmpdir(&block) ⇒ Object

If block given, temporary directory is deleted at the end of the block, and the value given by the block is returned.

If no block given, the path to the temp directory is returned as a FilePath. Don’t forget to delete it when you’re done.



18
19
20
21
22
23
24
25
26
# File 'lib/fun_with/files/file_path.rb', line 18

def self.tmpdir( &block )
  if block_given?
    Dir.mktmpdir do |d|
      yield d.fwf_filepath
    end
  else
    Dir.mktmpdir.fwf_filepath
  end
end

.tmpfile(ext = :tmp, &block) ⇒ Object

The file is created within a temporary directory



29
30
31
32
33
34
35
36
37
38
39
# File 'lib/fun_with/files/file_path.rb', line 29

def self.tmpfile( ext = :tmp, &block )
  filename = rand( 2 ** 64 ).to_s(16).fwf_filepath.ext( ext )
  
  if block_given?
    self.tmpdir do |tmp|
      yield tmp.join( filename ).touch
    end
  else
    self.tmpdir.join( filename ).touch
  end
end

Instance Method Details

#/(arg, &block) ⇒ Object



51
52
53
# File 'lib/fun_with/files/file_path.rb', line 51

def /( arg, &block )
  _yield_and_return( self.join( arg ), &block )
end

#[](*args, &block) ⇒ Object



55
56
57
# File 'lib/fun_with/files/file_path.rb', line 55

def []( *args, &block )
  _yield_and_return( self.join(*args), &block )
end

#append(content = nil, &block) ⇒ Object Also known as: <<



287
288
289
290
291
292
293
294
# File 'lib/fun_with/files/file_path.rb', line 287

def append( content = nil, &block )
  File.open( self, "a" ) do |f|
    f << content if content
    if block_given?
      yield f
    end
  end
end

#ascend(&block) ⇒ Object



641
642
643
644
645
646
647
648
649
650
# File 'lib/fun_with/files/file_path.rb', line 641

def ascend( &block )
  path = self.clone

  if path.root?
    yield path
  else
    yield self
    self.up.ascend( &block )
  end
end

#basename_and_extObject

base, ext = @path.basename_and_ext



463
464
465
# File 'lib/fun_with/files/file_path.rb', line 463

def basename_and_ext
  [self.basename_no_ext, self.ext]
end

#basename_no_extObject

Does not return a filepath

TODO: Why not?



330
331
332
# File 'lib/fun_with/files/file_path.rb', line 330

def basename_no_ext
  self.basename.to_s.split(".")[0..-2].join(".")
end

#descend(&block) ⇒ Object



630
631
632
633
634
635
636
637
638
639
# File 'lib/fun_with/files/file_path.rb', line 630

def descend( &block )
  path = self.clone

  if path.root?
    yield path
  else
    self.up.descend( &block )
    yield self
  end
end

#directoryObject

if it’s a file, returns the immediate parent directory. if it’s not a file, returns itself



480
481
482
# File 'lib/fun_with/files/file_path.rb', line 480

def directory
  self.directory? ? self : self.dirname
end

#dirname_and_basenameObject



469
470
471
472
# File 'lib/fun_with/files/file_path.rb', line 469

def dirname_and_basename
  warn("FilePath#dirname_and_basename() is deprecated.  Pathname#split() already existed, and should be used instead.")
  [self.dirname, self.basename]
end

#dirname_and_basename_and_extObject



474
475
476
# File 'lib/fun_with/files/file_path.rb', line 474

def dirname_and_basename_and_ext
  [self.dirname, self.basename_no_ext, self.ext]
end

#doesnt_exist?(&block) ⇒ Boolean Also known as: absent?

Returns:

  • (Boolean)


60
61
62
# File 'lib/fun_with/files/file_path.rb', line 60

def doesnt_exist?( &block )
  _yield_self_on_success( self.exist? == false, &block )
end

#empty?(&block) ⇒ Boolean

empty? has different meanings depending on whether you’re talking about a file or a directory. A directory must not have any files or subdirectories. A file must not have any data in it.

Returns:

  • (Boolean)

Raises:

  • (Exceptions::FileDoesNotExist)


315
316
317
318
319
320
321
322
323
324
325
# File 'lib/fun_with/files/file_path.rb', line 315

def empty?( &block )
  raise Exceptions::FileDoesNotExist unless self.exist?
  
  if self.file?
    is_empty = File.size( self ) == 0
  elsif self.directory?
    is_empty = Dir.entries( self ).length <= 2   # Dir.entries returns ".." and "." even when nothing else is there
  end
  
  _yield_self_on_success( is_empty, &block )
end

#entries(&block) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
# File 'lib/fun_with/files/file_path.rb', line 195

def entries( &block )
  rval = self.glob( :recurse => false )
  
  if block_given?
    for entry in rval
      yield entry
    end
  end
  
  rval
end

#expandObject



207
208
209
# File 'lib/fun_with/files/file_path.rb', line 207

def expand
  self.class.new( File.expand_path( self ) )
end

#ext(*args) ⇒ Object

Two separate modes.

With no arguments given, returns the current extension as a string (not a filepath). No leading period.

With an argument, returns the path with a .(arg) tacked onto the end. Result is the same whether a leading period is given or not. Multiple extensions can be given, and any object can be used so long as it responds sensibly to .to_s() (use at your own risk). Integers work, for example.



431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/fun_with/files/file_path.rb', line 431

def ext( *args )
  if args.length == 0
    split_basename = self.basename.to_s.split(".")
    split_basename.length > 1 ? split_basename.last : ""
  else
    
    append_to_path = args.compact.map{ |ex|
      ex.to_s.gsub( /^\./, '' )
    }.compact.join( "." )
    
    appended_to_path = "." + "#{append_to_path}" unless append_to_path.fwf_blank?
    
    self.class.new( "#{@path}#{appended_to_path}" )
  end
end

#ext?(*extensions, &block) ⇒ Boolean

asks if the .XXX at the end of the path matches one of the extensions given as an argument. If a block is given, the block will be run if the extension matches, ignored if no match is detected.

Returns:

  • (Boolean)


450
451
452
453
454
455
456
457
458
459
460
# File 'lib/fun_with/files/file_path.rb', line 450

def ext?( *extensions, &block )
  # Why is .to_str used here instead of to_s?
  acceptable_extensions = extensions.map do |e|
    ext = e.is_a?( Pathname ) ? e.to_str : e.to_s
    ext.gsub(/^\./,'')
  end
  
  ext_matches = acceptable_extensions.include?( self.ext )  
  
  _yield_self_on_success( ext_matches, &block )
end

#fwf_filepath {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:



498
499
500
501
# File 'lib/fun_with/files/file_path.rb', line 498

def fwf_filepath( &block )
  yield self if block_given?
  self
end

#glob(*args, &block) ⇒ Object

opts:

:flags  =>  File::FNM_CASEFOLD
            File::FNM_DOTMATCH
            File::FNM_NOESCAPE
            File::FNM_PATHNAME
            File::FNM_SYSCASE
            See Dir documentation for details.
              Can be given as an integer: (File::FNM_DOTMATCH | File::FNM_NOESCAPE)
              or as an array: [File::FNM_CASEFOLD, File::FNM_DOTMATCH]

:class  =>  [self.class] The class of objects you want returned (String, FilePath, etc.)
            Should probably be a subclass of FilePath or String.  Class.initialize() must accept a string
            [representing a file path] as the sole argument.

:recurse => [defaults true]
:recursive (synonym for :recurse)

:ext => []  A single symbol, or a list containing strings/symbols representing file name extensions.
            No leading periods kthxbai.
:sensitive => true : do a case sensitive search.  I guess the default is an insensitive search, so
                     the default behaves similarly on Windows and Unix.  Not gonna fight it.

:dots => true      : include dotfiles.  Does not include . and ..s unless you also
                     specify the option :parent_and_current => true.

If opts[:recurse] / opts[:ext] not given, the user can get the same
results explicitly with arguments like .glob("**", "*.rb")

:all : if :all is the only argument, this is the same as .glob(“**”, “*”)

Examples: @path.glob( “css”, “*.css” ) # Picks up all css files in the css folder @path.glob( “css”, :ext => :css ) # same @path.glob(:all) # same. Note: :all cannot be used in conjunction with :ext or any other arguments. Which may be a mistake on my part. @path.glob(“**”, “*”) # same TODO: depth argument? depth should override recurse. When extention given, recursion should default to true?

the find -depth argument says depth(0) is the root of the searched directory, any files beneath would be depth(1)


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
184
185
186
187
188
189
190
191
192
193
# File 'lib/fun_with/files/file_path.rb', line 120

def glob( *args, &block )
  args.push( :all ) if args.fwf_blank?
  opts = args.last.is_a?(Hash) ? args.pop : {}

  if args.last == :all
    all_arg_given = true
    args.pop
  else
    all_arg_given = false
  end

  flags = case (flags_given = opts.delete(:flags))
          when NilClass
            0
          when Array      # should be an array of integers or File::FNM_<FLAGNAME>s
            flags_given.inject(0) do |memo, obj|
              memo | obj
            end
          when Integer
            flags_given
          end

  flags |= File::FNM_DOTMATCH if opts[:dots]
  flags |= File::FNM_CASEFOLD if opts[:sensitive]   # case sensitive.  Only applies to Windows.

  recurse = if all_arg_given
              if opts[:recursive] == false || opts[:recurse] == false
                false
              else
                true
              end
            else
              opts[:recursive] == true || opts[:recurse] == true || false
            end

  if all_arg_given
    if recurse
      args = ["**", "*"]
    else
      args = ["*"]
    end
  else
    args.push("**") if recurse

    extensions = case opts[:ext]
    when Symbol, String
      "*.#{opts[:ext]}"
    when Array
      extensions = opts[:ext].map(&:to_s).join(',')
      "*.{#{extensions}}"                            # The Dir.glob format for this is '.{ext1,ext2,ext3}'
    when NilClass
      if args.fwf_blank?
        "*"
      else
        nil
      end
    end

    args.push( extensions ) if extensions
  end

  class_to_return = opts[:class] || self.class

  files = Dir.glob( self.join(*args), flags ).map{ |f| class_to_return.new( f ) }
  files.reject!{ |f| f.basename.to_s.match( /^\.\.?$/ ) } unless opts[:parent_and_current]

  if block_given?
    for file in files
      yield file
    end
  else
    files
  end
end

#grep(regex, &block) ⇒ Object

Returns a [list] of the lines in the file matching the given file. Contrast with



300
301
302
303
304
305
306
307
308
309
310
# File 'lib/fun_with/files/file_path.rb', line 300

def grep( regex, &block )
  return [] unless self.file?
  matching = []
  self.each_line do |line|
    matching.push( line ) if line.match( regex )
    yield line if block_given?
  end


  matching
end

#join(*args, &block) ⇒ Object Also known as: down



41
42
43
44
# File 'lib/fun_with/files/file_path.rb', line 41

def join( *args, &block )
  joined_path = self.class.new( super( *(args.map(&:to_s) ) ) )
  _yield_and_return( joined_path, &block )
end

#join!(*args, &block) ⇒ Object



46
47
48
49
# File 'lib/fun_with/files/file_path.rb', line 46

def join!( *args, &block )
  @path = self.join( *args, &block ).to_str
  _yield_and_return( self, &block )
end

#loadObject

TODO: succ_last : find the last existing file of the given sequence. TODO: succ_next : find the first free file of the given sequence



607
608
609
610
611
612
613
# File 'lib/fun_with/files/file_path.rb', line 607

def load
  if self.directory?
    self.glob( :recursive => true, :ext => "rb" ).map(&:load)
  else
    Kernel.load( self.expand )
  end
end

#not_a_file?(&block) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/fun_with/files/file_path.rb', line 64

def not_a_file?( &block )
  _yield_self_on_success( ! self.file?, &block )
end

#originalObject



488
489
490
# File 'lib/fun_with/files/file_path.rb', line 488

def original
  self.symlink? ? self.readlink.original : self
end

#original?(&block) ⇒ Boolean

Returns:

  • (Boolean)


484
485
486
# File 'lib/fun_with/files/file_path.rb', line 484

def original?(&block)
  _yield_self_on_success( !self.symlink?, &block )
end

#relative_path_from(dir) ⇒ Object

Basically Pathname.relative_path_from, but you can pass in strings



493
494
495
496
# File 'lib/fun_with/files/file_path.rb', line 493

def relative_path_from( dir )
  dir = super( Pathname.new( dir ) )
  self.class.new( dir )
end

#requirObject

Require ALL THE RUBY! This may be a bad idea…

Sometimes it fails to require a file because one of the necessary prerequisites hasn’t been required yet (NameError). requir catches this failure and stores the failed requirement in order to try it later. Doesn’t fail until it goes through a full loop where none of the required files were successful.



622
623
624
# File 'lib/fun_with/files/file_path.rb', line 622

def requir
  FunWith::Files::Requirements::Manager.require_files( self )
end

#root?(&block) ⇒ Boolean

Returns:

  • (Boolean)


626
627
628
# File 'lib/fun_with/files/file_path.rb', line 626

def root?(&block)
  _yield_self_on_success( self == self.up, &block)
end

#separatorObject

TODO : Not working as intended. def separator( s = nil )

# If s is nil, then we're asking for the separator
if s.nil?
  @separator || File::SEPARATOR
else
  @separator = s
end
# otherwise we're installing a separator

end



666
667
668
# File 'lib/fun_with/files/file_path.rb', line 666

def separator
  File::SEPARATOR
end

#size(units = :B) ⇒ Object



335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/fun_with/files/file_path.rb', line 335

def size( units = :B )
  sz = self.stat.size
  
  case units
  when :B
    sz
  when :K
    (sz / 1024.0).round(1)
  when :M
    (sz / 1048576.0).round(1)
  when :G
    (sz / 1073741824.0).round(1)
  end
end

#specifier(str, &block) ⇒ Object

puts a string between the main part of the basename and the extension or after the basename if there is no extension. Used to describe some file variant.

Example “/home/docs/my_awesome_screenplay.txt”.fwf_filepath.specifier(“final_draft”)

=> FunWith::Files::FilePath:/home/docs/my_awesome_screenplay.final_draft.txt

For the purposes of this method, anything after the last period in the filename is considered the extension.



549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'lib/fun_with/files/file_path.rb', line 549

def specifier( str, &block )
  str = str.to_s
  chunks = self.to_s.split(".")

  if chunks.length == 1
    chunks << str
  else
    chunks = chunks[0..-2] + [str] + [chunks[-1]]
  end

  f = chunks.join(".").fwf_filepath
  _yield_and_return( f, &block )
end

#succ(digit_count: SUCC_DIGIT_COUNT) ⇒ Object

Making this stricter, and failing when the formatting doesn’t meet expectations, rather than guessing wildly about what to do on corner cases.

This file is part of a sequence of files (file.000001.txt, file.000002.txt, file.000003.txt, etc.) ‘succ()` gives you the next file in the sequence. If no counter is present, a counter is added (file.dat –> file.000000.dat)

You can change the length of the sequence string by passing in the ‘digit_count` argument. Changing the length for a given sequence will lead to the function not recognizing the existing counter, and installing a new one after it.



513
514
515
516
517
518
# File 'lib/fun_with/files/file_path.rb', line 513

def succ( digit_count: SUCC_DIGIT_COUNT )
  directory_pieces = self.split
  succession_basename = Utils::Succession.get_successor_name( directory_pieces.pop, digit_count )
  
  return FilePath.new( * directory_pieces ) / succession_basename
end

#succession(opts = { digit_count: SUCC_DIGIT_COUNT, timestamp: false }) ⇒ Object

Returns the “wildcarded” version of the filename, suitable for finding related files with similar timestamps.

TODO: succession : enumerates a sequence of files that get passed to a block in order.



568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
# File 'lib/fun_with/files/file_path.rb', line 568

def succession( opts = { digit_count: SUCC_DIGIT_COUNT, timestamp: false } )
  if opts[:timestamp]
    opts[:timestamp_format] ||= "%Y%m%d%H%M%S%L"
    timestamp = Time.now.strftime( opts[:timestamp_format] )
    digit_count = timestamp.length
  else
    timestamp = false
    digit_count = opts[:digit_count]
  end

  chunks = self.basename.to_s.split(".")
  glob_stamp_matcher = '[0-9]' * digit_count

  # unstamped filename, no extension
  if chunks.length == 1
    original = chunks.first
    stamped = [original, glob_stamp_matcher].join(".")
  # stamped filename, no extension
  elsif chunks[-1].match( /^\d{#{digit_count}}$/ )
    original = chunks[0..-2].join(".")
    stamped = [original, glob_stamp_matcher].join(".")
  # stamped filename, has extension
  elsif chunks[-2].match( /^\d{#{digit_count}}$/ )
    original = [chunks[0..-3], chunks.last].flatten.join(".")
    stamped = [chunks[0..-3], glob_stamp_matcher, chunks.last].join(".")
  # unstamped filename, has extension
  else
    original = chunks.join(".")
    stamped = [ chunks[0..-2], glob_stamp_matcher, chunks[-1] ].flatten.join(".")
  end

  [self.dirname.join(original), self.dirname.glob(stamped)].flatten
end

#timestamp(format: :default, time: Time.now, splitter: ".", &block) ⇒ Object



521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'lib/fun_with/files/file_path.rb', line 521

def timestamp( format: :default, time: Time.now, splitter: ".", &block )
  timestamped_basename = Utils::Timestamp.timestamp( self.basename, format: format, time: time, splitter: splitter )
  
  directory_path = self.split[0..-2]
  
  # sigh....
  if directory_path.first.path == "." && self.path[0..1] != ".#{File::SEPARATOR}"
    directory_path.shift
  end
  
  if directory_path.length == 0
    timestamped_file = timestamped_basename.fwf_filepath
  else
    timestamped_file = FilePath.new( * self.split[0..-2], timestamped_basename ) 
  end
  
  _yield_and_return( timestamped_file, &block )
end

#to_pathnameObject



652
653
654
# File 'lib/fun_with/files/file_path.rb', line 652

def to_pathname
  Pathname.new( @path )
end

#touch(*args) {|touched| ... } ⇒ Object

Raises error if self is a file and args present. Raises error if the file is not accessible for writing, or cannot be created. attempts to create a directory

Takes an options hash as the last argument, allowing same options as FileUtils.touch

Yields:

  • (touched)


216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/fun_with/files/file_path.rb', line 216

def touch( *args, &block )
  args, opts = Utils::Opts.extract_opts_from_args( args )

  raise "Cannot create subdirectory to a file" if self.file? && args.length > 0
  touched = self.join(*args)

  dir_for_touched_file = case args.length
    when 0
      self.up
    when 1
      self
    when 2..Float::INFINITY
      self.join( *(args[0..-2] ) )
    end

  self.touch_dir( dir_for_touched_file, opts ) unless dir_for_touched_file.directory?
  FileUtils.touch( touched, ** Utils::Opts.narrow_file_utils_options( opts, :touch ) )

  yield touched if block_given?
  return touched
end

#touch_dir(*args) {|touched| ... } ⇒ Object

Takes the options of both FileUtils.touch and FileUtils.mkdir_p mkdir_p options will only matter if the directory is being created.

Yields:

  • (touched)


240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/fun_with/files/file_path.rb', line 240

def touch_dir( *args, &block )
  args, opts = Utils::Opts.extract_opts_from_args( args )

  touched = self.join(*args)
  if touched.directory?
    FileUtils.touch( touched, ** Utils::Opts.narrow_file_utils_options( opts, :touch ) )    # update access time
  else
    FileUtils.mkdir_p( touched, ** Utils::Opts.narrow_file_utils_options( opts, :mkdir_p ) )  # create directory (and any needed parents)
  end

  yield touched if block_given?
  return touched
end

#upObject

If called on a file instead of a directory, has the same effect as path.dirname



74
75
76
# File 'lib/fun_with/files/file_path.rb', line 74

def up
  self.class.new( self.join("..") ).expand
end

#without_ext(ext_val = nil) ⇒ Object

Returns the path, stripped of the final extension (.ARG). The result cannot destroy a dotfile or leave an empty path

"~/.bashrc".without_ext( .bashrc )  => "~/.bashrc",

if an argument is given, the final ext must match the given argument, or a copy of the unaltered path is returned.

Also:

Don't add a leading ./ when the original didn't have one
Case InSeNSItive, because I can't think of a use case for "only"
   strip the extension if the capitalization matches
Chews up any number of leading '.'s
For the moment,


364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/fun_with/files/file_path.rb', line 364

def without_ext( ext_val = nil )
  ext_chopper_regex = if ext_val.fwf_blank?
                        /\.+\w+$/i             # any ending "word characters"
                      else
                        # It's okay for the caller to make the leading period explicit
                        ext_val = ext_val.to_s.gsub( /^\./, '' )
                        /\.+#{ext_val}+$/i
                      end

  chopped_str = @path.gsub( ext_chopper_regex, "" )
  
  do_we_chop = if chopped_str == @path   # no change, then sure, why not?
                 true
               elsif chopped_str.fwf_blank? || chopped_str[-1] == self.separator() || chopped_str[-1] == "."
                 false
               else
                 true
               end
               
  self.class.new( do_we_chop ? chopped_str : @path )
  
  # # If the results fail to live up to some pre-defined
  #
  #
  #
  # # do we or don't we?
  # chop_extension = true
  #
  # #   Don't if there's an extension mismatch
  # #   Don't if the remainder is a /. (original was a dot_file)
  #
  #
  #
  #
  #
  #
  # _dirname, _basename, _ext = self.dirname_and_basename_and_ext
  # debugger if _basename =~ "hello"
  # ext_val = ext_val.to_s
  #
  # # 1) Only perform if the extension match the one given (or was a blank ext given?)
  #
  #
  #
  # new_path = @path.clone
  #
  # current_ext = self.ext
  #
  # e = e.to_s
  #
  # if e.fwf_present?
  #   new_path.gsub!( /\.#{e}$/, "" )
  #   result = self.gsub(/#{ not_beginning_of_line_or_separator}\.#{self.ext}$/, '')
  # else
  #   self.clone
  # end
  #
  # self.class.new( new_path )
end

#write(*args, &block) ⇒ Object



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/fun_with/files/file_path.rb', line 254

def write( *args, &block )
  args, opts = Utils::Opts.extract_opts_from_args( args )

  content = args.first

  if content == :random
    self.write_random_data( opts )
  else
    File.open( self, "w" ) do |f|
      f << content if content
      if block_given?
        yield f
      end
    end
  end
end

#write_random_data(sz, opts = {}) ⇒ Object

sz: number of bytes to write to the file opts => :overwrite or :append seed: What number to seed the random number generator with

FUTURE: May perform slowly on large sz inputs?



276
277
278
279
280
281
282
283
284
285
# File 'lib/fun_with/files/file_path.rb', line 276

def write_random_data( sz, opts = {} )
  rng = Random.new( opts[:seed] || Random::new_seed )
  mode = opts[:mode] || :overwrite

  if mode == :overwrite
    self.write( rng.bytes( sz ) )
  elsif mode == :append
    self.append( rng.bytes( sz ) )
  end
end