Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add File.atomic_write to prevent users from seeing half written files…

…. Useful for situations like Page Caching and the like. [Koz]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6262 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 203932ec88974acf8d86541cf0357cf9fc013143 1 parent df7ca38
@NZKoz NZKoz authored
View
2  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]
View
21 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
View
29 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
Please sign in to comment.
Something went wrong with that request. Please try again.