Ruby 1.8 vs 1.9 - destructive reject! operator
Why does this work the way it does? I thought it had something to do with pass-by-reference/value, but that's not the case. Does it have something to do with the new block scopes?
def strip_ids(array)
array.each{ |row| row.reject! {|k, v| k =~ /_id/ } }
end
class Foo
attr_accessor :array
def initialize
@array = []
@array << { :some_id => 1, :something => 'one' }
@array << { :some_id => 2, :something => 'two' }
@array << { :some_id => 3, :something => 'three'}
end
end
foo = Foo.new
puts strip_ids(foo.array).inspect
puts foo.array.inspect
开发者_运维技巧
##########################
#
# Output in ruby 1.8.7
#
# [{:some_id=>1, :something=>"one"}, {:some_id=>2, :something=>"two"}, {:some_id=>3, :something=>"three"}]
#
#
# Output in ruby 1.9.1
#
# [{:something=>"one"}, {:something=>"two"}, {:something=>"three"}]
#
In 1.9 regular expressions apparently can match symbols.
$ ruby -v -e 'puts((:hello =~ /llo/).inspect)'
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
false
$ 19/bin/!!
19/bin/ruby -v -e 'puts((:hello =~ /llo/).inspect)'
ruby 1.9.1p243 (2009-07-16 revision 24175) [i686-linux]
2
$
If you do the regex op with k.to_s
it will do the same thing on 1.8 and 1.9.
After digging into some of the C code for both versions of Ruby I can't seem to find where the relevant difference is. In Ruby 1.8.7 and 1.9.1 the =~ method is not defined for Symbol, but rather with Object. In 1.8.7 calling that method always returns false, while in 1.9.1 it always returns nil. Something must be different in how Symbols in 1.9.1 are recognized in for this particular operation since they are apparently type casted to Strings.
This is very odd behavior since it is completely undocumented and very different. I would suggest taking the question to the Ruby Core mailing list and see if any of the main hackers know what is going on.
精彩评论