You can change the options for your own usage. I like these options because worst covered files appeared on the top of the list. The HTML output is written in the folder doc/coverage. Then to run rcov you just enter.
rake rcov
No implicit conversion from nil to integer
If you got the following error.
no implicit conversion from nil to integer (TypeError)
You should edit the file /usr/lib/ruby/1.8/rexml/formatters/pretty.rb and replace this line
place = string.rindex(' ', width) # Position in string with last ' '
by this one
place = string.rindex(' ', width) || width # Position in string with last ' '
Stack level too depp
If you got the following error.
/usr/lib/ruby/1.8/rexml/formatters/pretty.rb:129:in `wrap': stack level too deep (SystemStackError)
You should edit the file /var/lib/gems/1.8/gems/rcov-0.8.1.2.0/lib/rcov/report.rb and replace the following line.
if RUBY_VERSION == "1.8.6" && defined? REXML::Formatters::Transitive
by this one
if RUBY_VERSION == "1.8.7" && defined? REXML::Formatters::Transitive
Download a file is a source of problems. Host can be down, bandwith can be too slow, file can be too big, download takes too much time … This is an important point for a program which download many files. Furthemore it’s often useful to notice users how much of a file is downloaded and when it will be finished.
That’s why I wrote a little module named Net::HTTP::Stats. This module count the number of bytes read, and then set correctly some variables like rate, estimated left time, percent of bytes read and so on. I used this module for a web bot, which downloads many many web pages, and it’s working really well.
The following code download Ruby and print the percent of download, the rate and the estimated remaining time.
require 'net/http'
require 'net/http/stats'
content = ''
uri = URI.parse('http://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.gz')
response = Net::HTTP.get_response_with_stats(uri) do |resp, bytes|
content << bytes
puts "#{resp.bytes_percent}% downloaded at #{(resp.bytes_rate / 1024).to_i} Ko/s, remaining # {resp.left_time.to_i} seconds"
end
This script will print something like:
13% downloaded at 59 Ko/s, remaining 65 seconds
The module Net::HTTP::Stats add the get_response_with_stats method. It works like get_response. However the block have a 2nd argument which contains bytes. It’s not possible to get bytes via response.read_body, because bytes have been already read to set the stats.
From this work it’s easy to write rules:
Minimum rate
Maximum file size
Maximum time
That’s why I wrote a 2nd method called get_response_with_rules. Rules are stored in a hash. Like get_response_with_stats the block takes 2 same arguments.
rules = {
# Download is interrupted if spent time is greater (in sec).
:max_time => 5 * 60,
# Download is interrupted if estimated time is greater (in sec).
:max_left_time => 5 * 60,
# Download is interrupted if body is greater (in byte).
:max_size => 50 * 1024 * 1024,
# Wait some time before checking max_time and max_left_time (in sec).
# something between 5 and 20 seconds should be good.
:min_time => 15
}
content = ''
uri = URI.parse('http://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.gz')
response = Net::HTTP.get_response_with_rules(uri, rules) do |resp, bytes|
content << bytes
end
To use Net::HTTP::Stats you have to copy the « lib » folder into your project or any location pointed by your $LOAD_PATH. Any feed back is welcome.
Sometimes applications need to be fast. Unfortunalty scripting languages like Ruby are slow. However rewriting an entire application isn’t the most efficient way. Furthemore the part that need to be faster isn’t really of an outstanding size in terms of code. That’s why Ruby inline is an excellent solution.
The goal is to replace the slow Ruby code by C code. It could be 5 or 20 lines in most of cases. Thanks to Ruby Inline it’s possible to rewrite methods in C directly in the ruby source. The C code is compiled on the fly only once. In less than 10 lines I decrease execution time of 40% in the example of this article. The most impressive is that it took me 15 minutes to do it without knowing Ruby Inline before. I think Ruby Inline is a really good tool.
For example we will try to optimise the class Hash32. This class computes the hash of a string by mixing characters by block of 4 bytes. The result is an integer of 32 bytes. The following sample code is extracted from file hash32.rb.
class Hash32
def compute(str)
i = 0
sum = 0
size = str.size
str = String.new(str)
missing = 4 - (size % 4)
str << '_' * missing if missing != 4
while i < size
sum ^= mix(str[i], str[i+1], str[i+2], str[i+3])
i += 4
end
sum
end
def mix(a, b, c, d)
(a << 24) + (b << 16) + (c << 8) + d
end
end
I decided to optimise only the method mix because it don’t required a lot of knowledge about Ruby C API. I decided to write the fast version in an other file, called hash32.c.rb, to be more elegant and useful.
class Hash32
require 'inline'
c_inline = <<__INLINE__
VALUE mix(unsigned int a, unsigned int b, unsigned int c, unsigned int d)
{
return UINT2NUM((a << 24) + (b << 16) + (c << 8) + d);
}
__INLINE__
inline do |builder| builder.c(c_inline) end
rescue LoadError => e
end
First of all we have to load the inline library. Then we write the C code for the mix method. Ruby Inline translates most of basic types. However in this case we need the macro UINT2NUM. I advice you to read the chapter Extending Ruby of the programming Ruby book. You d’ont have to be a Ruby C API guru to optimize with Ruby Inline. But it’s better to have some basic knowledge about it.
Ruby Inline is not included in the Ruby standard library. Moreover Ruby Inline requires a C compiler like gcc and Ruby headers to work. That’s why it may not work on all platforms. The best solution is to use the C version where Ruby Inline is available otherwise the slow version of mix. This job is done by the rescue LoadError if require ‘inline’ failes.
You can install Ruby Inline via gem.
gem install RubyInline
And don’t forget to install Ruby headers too. You can download the complete source code. There is a file named collisions.rb that tests the hash sum with about 90 000 words. The script is executed in 7.2 seconds in pure Ruby and in 4.3 seconds with the inline version of mix.