8

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.

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]

Community
  • 1
  • 1
Diadistis
  • 12,086
  • 1
  • 33
  • 55
  • 7
    `the code was actually fine, but it wasn't` - been there. – BroiSatse Oct 10 '14 at 11:40
  • 5
    both methods are identical. there is no semantic difference between `{}` and `do end` blocks – phoet Oct 10 '14 at 12:57
  • 1
    I've added more of the code in question, specifically around the `IO#read` method that is happening – sethvargo Oct 10 '14 at 13:27
  • 3
    According to [the pickaxe](https://pragprog.com/book/ruby4/programming-ruby-1-9-2-0), *"they have different precedences: the braces bind more tightly than the do/end pairs".* I don't know how that would explain this weird behaviour, but might give a hint to someone smarter than me to figure out. :) – cassianoleal Oct 10 '14 at 13:35
  • @Diadistis (or anyone else who can), please edit the question and/or tag it to emphasize that this is happening on Windows. Until somebody tries to recreate it on a POSIX OS, we don't know if this is a "ruby" question or a "ruby on windows" question. – Matt Campbell Oct 14 '14 at 17:21
  • @MattCampbell done. Have you tested the fix yourself? Does it work for you? – Diadistis Oct 14 '14 at 19:23
  • @Diadistis change the extension, `metadata.json` to `metadata.rb`. – seoyoochan Dec 22 '15 at 22:29
  • @seoyoochan What difference would that make? – Charlie Harding Dec 24 '15 at 09:34
  • @CharlieHarding because Chef was built on Rub so that Chef interprets metadata.rb. Read `metadata.rb` section here. https://docs.chef.io/cookbook_repo.html – seoyoochan Dec 24 '15 at 09:50
  • That file error is coming from the guts of the C language underbelly of Ruby's IO functionality. As others have said, I don't believe it has anything to do with your syntax. In cases like this I find it useful to start irb and try the simplest possible useful operation -- in this case, I would simply try opening the file without doing anything else. I suspect this would trigger the error. There may have been some difference in the presence or name of the file in your attempts. – Keith Bennett Apr 19 '16 at 10:06

1 Answers1

1

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 !!!

Gupta
  • 8,882
  • 4
  • 49
  • 59