DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Switch_around

12.21.2005
| 4019 views |
  • submit to reddit
        
require 'enumerator'

# Returns an object of the argument's class with each_slice of 2 switched around.
# Works on any object that mixes in #each
# 
# Examples:
# switch_around("foo!")       #=> of!o
# switch_around((1..10).to_a) #=> [2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
def switch_around(data)
  switched_data = data.class.new
  
  # When appending to a string ints will have #chr called on them, so protect against 
  # error about sending a message to nil. b will only be nil when the  collection is 
  # an odd length. Of course, this creates a bug. For example we could have an Array with 
  # embedded nils, so we must also check if it is a String (again...)
  switch_proc = lambda do |a,b|
    switched_data << b unless b.nil? and data.is_a?(String)
    switched_data << a
  end
  
  # String#each enumerates over lines, so we must change it to enumerate over bytes.
  if data.is_a?(String)
    data.to_enum(:each_byte).each_slice(2) { |a,b| switch_proc.call(a, b) }
  else
    data.each_slice(2) { |a,b| switch_proc.call(a,b) }
  end
  
  switched_data
end