This blog is part of our Ruby 3.0 series.

Ruby 3 adds a new method, except, to the Hash class. Hash#except returns a hash excluding the given keys and their values.

Why do we need Hash#except?

At times, we need to print or log everything except some sensitive data. Let’s say we want to print user details in the logs but not passwords.

Before Ruby 3 we could have achieved it in the following ways:

irb(main):001:0> user_details = { name: 'Akhil', age: 25, address: 'India', password: 'T:%g6R' }

# 1. Reject with a block and include?
irb(main):003:0> puts user_details.reject { |key, _| key == :password }
=> { name: 'Akhil', age: 25, address: 'India' }

# 2. Clone the hash with dup, tap into it and delete that key/value from the clone
irb(main):005:0> puts user_details.dup.tap { |hash| hash.delete(:password) }
=> { name: 'Akhil', age: 25, address: 'India' }

We know that ActiveSupport already comes with Hash#except but for a simple Ruby application using ActiveSupport would be overkill.

Ruby 3

To make the above task easier and more explicit, Ruby 3 adds Hash#except to return a hash excluding the given keys and their values:

irb(main):001:0> user_details = { name: 'Akhil', age: 25, address: 'India', password: 'T:%g6R' }
irb(main):002:0> puts user_details.except(:password)
=> { name: 'Akhil', age: 25, address: 'India' }

irb(main):003:0> db_info = YAML.safe_load(File.read('./database.yml'))
irb(main):004:0> puts db_info.except(:username, :password)
=> { port: 5432, database_name: 'example_db_production' }

Check out the commit for more details. Discussion around it can be found here.