Class: File

Inherits:
Object show all
Defined in:
lib/garcon/core_ext/file.rb

Class Method Summary collapse

Class Method Details

.atomic_idObject


26
27
28
29
# File 'lib/garcon/core_ext/file.rb', line 26

def self.atomic_id
  @atomic_id ||= 0
  @atomic_id += 1
end

.atomic_open(file_name, mode = "r", temp_dir = nil, &block) ⇒ Object

Same as `File.open`, but acts on a temporary copy of named file, copying the file back to the original on completion.


37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/garcon/core_ext/file.rb', line 37

def self.atomic_open(file_name, mode="r", temp_dir=nil, &block)
  temp_dir  = temp_dir || Dir.tmpdir
  temp_file = Tempfile.new("#{aomtic_id}-" + basename(file_name), temp_dir)

  if File.exist?(file_name)
    FileUtils.cp(file_name, temp_file)
  end

  open(temp_file, mode, &block)

  FileUtils.cp(temp_file, file_name)
end

.atomic_write(file_name, temp_dir = nil) {|temp_file| ... } ⇒ Object

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

File.atomic_write("important.txt") do |file|
  file.write("hello")
end

If your temporary directory is not on the same filesystem as the file you're trying to write, you can provide a different temporary directory.

File.atomic_write("important.txt", "tmp") do |file|
  file.write("hello")
end

NOTE: This method is not a common core extension and is not loaded automatically when using require 'facets'.

CREDIT: David Heinemeier Hansson

Yields:

  • (temp_file)

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
# File 'lib/garcon/core_ext/file.rb', line 72

def self.atomic_write(file_name, temp_dir=nil)
  temp_dir  = temp_dir || Dir.tmpdir
  temp_file = Tempfile.new(basename(file_name), temp_dir)

  yield temp_file
  temp_file.close

  begin
    ## Get original file permissions
    old_stat = stat(file_name)
  rescue Errno::ENOENT    ## No old permissions, write a temp file to determine the defaults

    check_name = join(dirname(file_name), ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}")
    open(check_name, "w") { }
    old_stat = stat(check_name)
    unlink(check_name)
  end

  ## Overwrite original file with temp file
  FileUtils.mv(temp_file.path, file_name)

  ## Set correct permissions on new file
  chown(old_stat.uid, old_stat.gid, file_name)
  chmod(old_stat.mode, file_name)
end

.read_list(filepath, options = {}) ⇒ Object

Reads in a file, removes blank lines and removes lines starting with '#' and then returns an array of all the remaining lines.

Thr remark indicator can be overridden via the :omit: option, which can be a regualar expression or a string that is match against the start of a line.

CREDIT: Trans


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/garcon/core_ext/file.rb', line 107

def self.read_list(filepath, options={})
  chomp = options[:chomp]
  omit  = case options[:omit]
          when Regexp
            omit
          when nil
            /^\s*\#/
          else
            /^\s*#{Regexp.escape(omit)}/
          end

  list = []
  readlines(filepath).each do |line|
    line = line.strip.chomp(chomp)
    next if line.empty?
    next if omit === line
    list << line
  end
  list
end