pitosalas
pitosalas

Reputation: 10882

Using new Ruby pattern matching to check if a hash has certain keys

I want to use the new Ruby 3 feature in this very simple case. I know it must be possible but I have not figured it out from the documentation.

Given a hash, I want to check that it has certain keys. I don't mind if it has others in addition. And I want to do this with pattern matching (or know that it is impossible.) I also don't want to use a case statement which seems overkill.

{name: "John", salary: 12000, email: "[email protected]" } 
  1. Raise an error if the hash does not have name, and email as strings and salary as a number.

  2. Use the contruct in an if or other conditional?

  3. And what if the hash has strings as keys (which is what I get from JSON.parse) ?

    {"name" => "John", "salary" => 12000, "email" => "[email protected]" }

Upvotes: 0

Views: 1729

Answers (2)

cremno
cremno

Reputation: 4927

You're looking for the => operator:

h = {name: "John", salary: 12000, email: "[email protected]" }
h => {name: String, salary: Numeric, email: String} # => nil

With an additional pair (test: 0):

h[:test] = 0
h => {name: String, salary: Numeric, email: String} # => nil

Without the :name key:

h.delete :name
h => {name: String, salary: Numeric, email: String} # key not found: :name (NoMatchingPatternKeyError)

With the :name key but the class of its value shouldn't match:

h[:name] = 1
h => {name: String, salary: Numeric, email: String} # String === 1 does not return true (NoMatchingPatternKeyError)

A strict match:

h[:name] = "John"
h => {name: String, salary: Numeric, email: String} # => rest of {:test=>0} is not empty

The in operator returns a boolean value instead of raising an exception:

h = {name: "John", salary: 12000, email: "[email protected]" }
h in {name: String, salary: Numeric, email: String} # => true
h[:name] = 1
h in {name: String, salary: Numeric, email: String} # => false

Upvotes: 4

steenslag
steenslag

Reputation: 80065

"I also don't want to use a case statement which seems overkill." case is just the syntax for pattern matching. AFAIK it is not the same as a case when, it's a case in.

h = {name: "John", salary: 12000, email: "[email protected]", other_stuff: [1] } 
case h
  in {name: String, salary: Integer, email: String}
    puts "matched"
  else
    raise "#{h} not matched"
end

Upvotes: 3

Related Questions