diff options
| -rw-r--r-- | activesupport/CHANGELOG | 2 | ||||
| -rw-r--r-- | activesupport/lib/active_support/core_ext/file.rb | 21 | ||||
| -rw-r--r-- | activesupport/test/core_ext/file_test.rb | 29 | 
3 files changed, 52 insertions, 0 deletions
| diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 622ddf1a94..09ea8159a7 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@  *SVN* +* Add File.atomic_write,  allows you to write large files in an atomic manner, preventing users from seeing half written files.  [Koz] +  * Allow users to provide custom formatters to Logger. [aeden]  * Hash#to_query CGI-escapes its keys.  [Jeremy Kemper] diff --git a/activesupport/lib/active_support/core_ext/file.rb b/activesupport/lib/active_support/core_ext/file.rb new file mode 100644 index 0000000000..cd43be37e3 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/file.rb @@ -0,0 +1,21 @@ +require 'tempfile' + +# 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.file") do |file| +#    file.write("hello") +#  end +# +# If your temp 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("/data/something.imporant", "/data/tmp") do |f| +#   file.write("hello") +# end +def File.atomic_write(file_name, temp_dir = Dir.tmpdir) +  temp_file = Tempfile.new(File.basename(file_name), temp_dir) +  yield temp_file +  temp_file.close +  File.rename(temp_file.path, file_name) +end
\ No newline at end of file diff --git a/activesupport/test/core_ext/file_test.rb b/activesupport/test/core_ext/file_test.rb new file mode 100644 index 0000000000..a7a8324125 --- /dev/null +++ b/activesupport/test/core_ext/file_test.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../abstract_unit' + +class AtomicWriteTest < Test::Unit::TestCase +   +  def test_atomic_write_without_errors +    contents  = "Atomic Text" +    File.atomic_write(file_name) do |file| +      file.write(contents) +      assert !File.exists?(file_name) +    end +    assert File.exists?(file_name) +    assert_equal contents, File.read(file_name) +  ensure +    File.unlink(file_name) +  end +   +  def test_atomic_write_doesnt_write_when_block_raises +    File.atomic_write(file_name) do |file| +      file.write("testing") +      raise "something bad" +    end +  rescue +    assert !File.exists?(file_name) +  end +   +  def file_name +    "atomic.file" +  end +end | 
