if __name__ is None
if __name__ is None

Reputation: 11533

Ruby and File.read

I am building a build automation script for my javascripts. I've never used File.read before, but I've decided to give it a try, since it saves a line of code.

So here is my code:

require "uglifier"
require "debugger"

@buffer = ""

# read contents of javscripts
%w{crypto/sjcl.js miner.js}.each do |filename|
  debugger
  File.read(filename) do |content|
    @buffer += content
  end
end

# compress javascripts
@buffer = Uglifier.compile(@buffer)

# TODO insert js in html

# build the html file
File.open("../server/index.html", "w") do |file|
  file.write @buffer
end

But, it doesn't work. @buffer is always empty.

Here is the debugging process:

(rdb:1) pp filename
"crypto/sjcl.js"
(rdb:1) l
[4, 13] in build_script.rb
   4  @buffer = ""
   5  
   6  # read contents of javscripts
   7  %w{crypto/sjcl.js miner.js}.each do |filename|
   8    debugger
=> 9    File.read(filename) do |content|
   10      @buffer += content
   11    end
   12  end
   13  
(rdb:1) irb
2.0.0-p0 :001 > File.read(filename){ |c| p c }
 => "...very long javascript file content here..."

As you can see, in the irb, File.read works fine. If I put debugger breakpoint within the File.read block however, it never breaks into debugger. Which means the block itself is never executed?

Also, I've checked the documentation, and File.read is mentioned nowhere. http://ruby-doc.org/core-2.0/File.html

Should I just ditch it, or am I doing something wrong?

%w{crypto/sjcl.js miner.js}.each do |filename|
  File.open(filename, 'r') do |file|
    @buffer << file.read
  end
end

This works just fine. However I'm still curious whats up with File.read

Upvotes: 0

Views: 1261

Answers (1)

Dogbert
Dogbert

Reputation: 222388

File.read doesn't accept a block, it returns the contents of the file as a String. You need to do:

@buffer += File.read(filename)

The reason debugger shows the contents is because it prints the return value of the function call.

Now, for some solicited advice, if you don't mind:

  1. There's no need of doing @buffer, you can simply use buffer
  2. Instead of var += "string", you can do var << string. + creates a new String object, while << modifies it in-place, and thus is faster and efficient. You're mutating it anyways by doing +=, so << will do the same thing.
  3. Instead of File.open then file.write, you can do File.write directly if using Ruby 2.0.

Your final code becomes (untested):

require "uglifier"
require "debugger"

buffer = ""

# read contents of javscripts
%w{crypto/sjcl.js miner.js}.each do |filename|
  buffer << File.read(filename)
end

# compress javascripts
buffer = Uglifier.compile(buffer)

# TODO insert js in html

# build the html file
File.write("../server/index.html", buffer)

If you'd like to make it more functional, I have more suggestions, please comment if you'd like some. :)

Upvotes: 3

Related Questions