Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird File.open behavior when using different closure types in Ruby

Tags:

windows

ruby

I started learning Chef to manage our servers and I stumbled in a very weird (in my opinion) behavior in Ruby. I do not know Ruby so this might be just a misunderstanding from my part.

The error I was getting was

`delete': Permission denied - [some path]/metadata.json (Errno::EACCES)

Since I knew for sure that it was not actually about permissions, the next logical thing was to check for file locking. After digging a bit through the relevant code, I discovered that there is a method that produces a checksum for each file.

  • load_root
  • file_metadata
  • checksum
  • md5_checksum_for_file
  • generate_md5_checksum_for_file
  • checksum_file
def checksum_file(file, digest)
  File.open(file, 'rb') { |f| checksum_io(f, digest) }
end

def checksum_io(io, digest)
  while chunk = io.read(1024 * 8)
    digest.update(chunk)
  end
  digest.hexdigest
end

Having found that, I searched a bit and found an answer about closing files in Ruby and it seemed that the code was actually fine... but it was not. I tried to change the method to the "block format" and it worked without error:

def checksum_file(file, digest)
  File.open(file, 'rb') do |f|
    checksum_io(f, digest)
  end
end

Can someone please explain the difference between the two versions of the code?

-- Edit --

It seems that this problem occurs only in Windows and maybe only when using the ruby provided by ChefDK 0.3.0 :

ruby 2.0.0p451 (2014-02-24) [i386-mingw32]

like image 493
Diadistis Avatar asked Oct 10 '14 11:10

Diadistis


1 Answers

Answer of your question

Can someone please explain the difference between the two versions of the code?

  • Block always return something so do end and and { ... } dose't really matter This is just personnel programming preference.

  • There are two different convention with block i'm going to dispense to you now and it up to you which religion you want to subscribe to.

First religion says that

when you have a single line or single line block you would use the curly braces And if you have a multi line block you would use do and end.

words.each { |word| puts word }  # single line or single line block

words.each do |word|  # multi line block
  puts word
  p 1
end

Second religion says that

If your block simply does something has side effect and you dont care about the return value you might put do and end

words.each do |word|
  puts word
end

where as if you do care about return value you would use { ... }

back_words = words.map{ |word| word.reverse }

hope I answere your question !!!

like image 174
Gupta Avatar answered Nov 05 '22 05:11

Gupta