The rule “Prefer atomic file operations” is designed to promote the use of atomic operations when interacting with files or directories. This is important because non-atomic file operations can lead to race conditions, where the state of a file or directory changes between the time you check its state and the time you perform an operation on it. For example, if you check whether a directory exists and then try to create it if it doesn’t, another process could create the directory after you check, but before you create it, leading to an error.
In Ruby, you can avoid this problem by using methods from the FileUtils module, which provide atomic operations. For example, instead of checking whether a directory exists and then creating it if it doesn’t, you can use the FileUtils.mkdir_p method, which will create the directory if it doesn’t exist, and do nothing if it does.
Non-compliant code often checks for the existence of a file or directory using File.exist? or Dir.exist? and then performs a file operation. To fix this, replace these checks and operations with equivalent atomic operations. For example, replace unless Dir.exist?(path); FileUtils.mkdir(path); end with FileUtils.mkdir_p(path). Similarly, replace if File.exist?(path); FileUtils.remove(path); end with FileUtils.rm_f(path). This will ensure that your file operations are atomic, and safe from race conditions.
Non-Compliant Code Examples
# The failing snippets check if a file or directory exists,# then call a function from FileUtils on that file or directory.unlessDir.exist?(path)FileUtils.mkdir(path)endunlessnotFile.exist?(path)FileUtils.remove(path)endifFile.exist?(path)FileUtils.remove(path)endif!Dir.exist?(path)FileUtils.mkdir(path)end
Compliant Code Examples
# Preferred alternative to check-if-exist-then-mkdirFileUtils.mkdir_p(path)# Preferred alternative to check-if-exist-then-rmFileUtils.rm_f(path)# More than one argument to the operationifFile.exist?(path)FileUtils.doSomething(path,arg)end# These use different modules or methodsunlessFoo.exist?(path)FileUtils.mkdir(path)endunlessDir.exists?(path)FileUtils.mkdir(path)endunlessDir.exist?(path)FileUtilities.mkdir(path)end# These check one thing then operate on another thingunlessDir.exist?(path)FileUtils.mkdir(other_path)end# These check one thing then operate on another thingifFile.exist?(path)FileUtils.remove(other_path)end
Seamless integrations. Try Datadog Code Analysis
Datadog Code Analysis
Try this rule and analyze your code with Datadog Code Analysis
How to use this rule
1
2
rulesets:- ruby-best-practices # Rules to enforce Ruby best practices.
Create a static-analysis.datadog.yml with the content above at the root of your repository
Use our free IDE Plugins or add Code Analysis scans to your CI pipelines