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:
1 2irb(main):001:0> user_details = { name: 'Akhil', age: 25, address: 'India', password: 'T:%g6R' } 3 4# 1. Reject with a block and include? 5irb(main):003:0> puts user_details.reject { |key, _| key == :password } 6=> { name: 'Akhil', age: 25, address: 'India' } 7 8# 2. Clone the hash with dup, tap into it and delete that key/value from the clone 9irb(main):005:0> puts user_details.dup.tap { |hash| hash.delete(:password) } 10=> { name: 'Akhil', age: 25, address: 'India' } 11
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:
1 2irb(main):001:0> user_details = { name: 'Akhil', age: 25, address: 'India', password: 'T:%g6R' } 3irb(main):002:0> puts user_details.except(:password) 4=> { name: 'Akhil', age: 25, address: 'India' } 5 6irb(main):003:0> db_info = YAML.safe_load(File.read('./database.yml')) 7irb(main):004:0> puts db_info.except(:username, :password) 8=> { port: 5432, database_name: 'example_db_production' } 9
Check out the commit for more details. Discussion around it can be found here.