jekyll/mercenary — pull request #35 by atombender (2014-07-12 03:53:30+00:00)
Title: Use option object as key in the command's @map hash

This fixes an intermittent problem that causes Mercenary to parse the completely wrong options. For example, I had a `--workers N` option. Every now and then — in fact, very often, sometimes on _every_run — I would end up with the rather curious options hash `{"show_version" => 2}`, when the command line was in fact `--workers 2`.

The reason is the use of `Option#hash` as the key in `@map`. The `hash` method used `&` to compute its hash, which of course vastly reduces the space of numbers and in fact tends to produce 0 — instead of the traditional `^` (XOR). So the likelyhood of having collisions is in fact extremely high.

This small patch changes the operator, but more importantly, uses the option object as the key, since the very simple `hash` function is not guaranteed to produce unique keys. (Doing `map[key.hash]` to store objects in a Ruby hash is never wise. The whole point of dynamically built hash tables is to be compact while support collisions.)

To illustrate the problem, the following script (without this patch) will show how fast you end up with a zero hash:

```ruby
loop do
s = ""
rand(100).times do
s << rand(100).to_s
end
if Mercenary::Option.new(:foo, ["-#{s}", s]).hash == 0
puts "oops"
end
end
```