Today, another snippet from the category don't try at home, might have unforeseeable consequences!
Constant assignment¹ is not permanent in Ruby, so it is perfectly valid to do this:
module A
end
class B
def initialize
p 42
end
end
A, B = B, A
# warning: already initialized constant A
# warning: previous definition of A was here
# warning: already initialized constant B
# warning: previous definition of B was here
A.new #=> #<B:0x00000002744008>
# 42
¹ As a side note: There is also Module#remove_const, which will delete the constant, but not the module! Quoting the documentation: "If that constant referred to a module, this will not change that module's name and can lead to confusion"
o = Object.send(:remove_const, :Object)
Object.constants # NameError: uninitialized constant Object
o # => Object
The Ruby Shuffle
Developing the swapping idea further, for maximal confusion:
require 'stringio'
def shuffle_ruby(n=rand(50))
mod, os, e, sio = Module, ObjectSpace, Exception, StringIO
stderr, $stderr = $stderr, sio.new
n.times{
begin
m1 = os.each_object(mod).to_a.sample
m2 = os.each_object(mod).to_a.sample
puts "Swap #{m1} and #{m2}"
eval "#{m1}, #{m2} = #{m2}, #{m1}"
rescue e
end
}
$stderr = stderr
puts "Ruby shuffled (#{n} swaps)"
end
More Idiosyncratic Ruby
- Please Comment on GitHub
- Next Article: The Art of Arguments
- Previous Article: Top Level Binding