Better deep nested hash handling in ruby

Here is a nice Ruby trick a co-worked pointed me to:

Let's take this deep nested hash:
"ReservationsList" => {
  "HotelReservation" => {
    "RoomStayReservation" => "true", "ResStatus" => "In-House", "UniqueID" => {
      "Type" => "14", "ID" => "961279381"
    }, "Services" => {
      "Service" => {
        "TPA_Extensions" => {
          "TPA_Extension" => {
            "WiFiFees" => {
              "NumberConnections" => "4", "ConnectionType" => "F"
            }, "RATES" => {
              "xmlns" => "", "DAYS" => "1", "CONNECT" => "0"
            }
          }
        }
      }
    }, "ResGuests" => {
      "ResGuest" => {
        "Profiles" => {
          "ProfileInfo" => {
            "UniqueID" => {
              "Type" => "21", "ID" => "766353055"
            }, "Profile" => {
              "TPA_Extensions" => {
                "TPA_Extension" => {
                  "DRI_INFO" => {
                    "MemberLevel" => "0", "GuestType" => "GST", "OwnerStay" => "N", "PackCode" => "NA", "Amenities" => "NA", "WifiFeeCode" => "N", "MktProgramCode" => "OT"
                  }
                }
              }, "Customer" => {
                "PersonName" => {
                  "Surname" => "Jjonat", "GivenName" => "Jonathan K"
                }
              }
            }
          }
        }
      }
    }, "RoomStays" => {
      "RoomStay" => {
        "BasicPropertyInfo" => {
          "HotelCode" => "MDR"
        }, "RoomRates" => {
          "RoomRate" => {
            "RoomID" => "31315", "BookingCode" => "BON", "GuestCounts" => {
              "GuestCount" => {
                "Count" => "1"
              }
            }
          }
        }, "TimeSpan" => {
          "Start" => "2020-05-08", "End" => "2020-05-22"
        }
      }
    }
  }
}
}
To get the MemberLevel you could do:
ml = room_info["ReservationsList"]["HotelReservation"]["ResGuests"]["ResGuest"]["Profiles"]["ProfileInfo"]["Profile"]["TPA_Extensions"]["TPA_Extension"]["DRI_INFO"]["MemberLevel"]
Problem is if a level is missing it explodes. For example I changed DRI_INFO for DRI_INFO1 which does not exists:
irb(main):009:0> room_info["ReservationsList"]["HotelReservation"]["ResGuests"]["ResGuest"]["Profiles"]["ProfileInfo"]["Profile"]["TPA_Extensions"]["TPA_Extension"]["DRI_INFO1"]["MemberLevel"]Traceback (most recent call last):        2: from /Users/courchea/.rbenv/versions/2.5.0/bin/irb:11:in `<main>'        1: from (irb):9NoMethodError (undefined method `[]' for nil:NilClass)
Or you doing use dig:
ml = room_info.dig("ReservationsList", "HotelReservation", "ResGuests", "ResGuest", "Profiles", "ProfileInfo", "Profile", "TPA_Extensions", "TPA_Extension", "DRI_INFO", "MemberLevel")
dig will protect you against missing nesting levels. Doing the same change DRI_INFO for DRI_INFO1 we are now safe:
irb(main):010:0> room_info.dig("ReservationsList", "HotelReservation", "ResGuests", "ResGuest", "Profiles", "ProfileInfo", "Profile", "TPA_Extensions", "TPA_Extension", "DRI_INFO1", "MemberLevel") => nil

Comments

Popular Posts