Isn't this intending to check if names.is_a?(Hash) :question:
Let the tests warn
Prefer Encoding::ASCII_8BIT over "binary"

this slightly reduces the garbage Strings, and makes the code semantically more correct
Use existing constant instead of mortal String being
Reduce number of String objects while `underscore`ing
Avoid creating a concatenated String which will never actually be used
Prefer Hash[] over inject({})

basically this is faster and reads better
Avoid creating extra Range objects
String#tr runs faster than gsub
String#delete must be faster than gsub
Destructive! operations! for less memory consumption!!!
String interpolations are basically faster than concatenations
Skip scanning through empty Strings