Ruby - USA State PORO
A simple PORO that represents a USA state.
class UsState
attr_reader :name, :abbreviation
def initialize(name_or_abbreviation)
@name = self.class.state_name_from_abbreviation(name_or_abbreviation)
@abbreviation = self.class.abbreviate_state_name(@name)
end
def valid?
name.present? && abbreviation.present?
end
class << self
def state_name_from_abbreviation(name_or_abbreviation)
return if name_or_abbreviation.blank?
return name_or_abbreviation if valid_state_name?(name_or_abbreviation)
US_STATES[name_or_abbreviation.to_s.upcase]
end
def abbreviate_state_name(state_name)
return if state_name.blank?
return state_name.to_s.upcase if valid_abbreviation?(state_name)
US_STATES.invert[state_name]&.upcase
end
def valid_abbreviation?(word)
word&.length == 2 && US_STATES[word.to_s.upcase]
end
def valid_state_name?(word)
word&.length != 2 && US_STATES.invert[word]
end
end
US_STATES = {
"AK" => "Alaska",
"AL" => "Alabama",
"AR" => "Arkansas",
"AS" => "American Samoa",
"AZ" => "Arizona",
"CA" => "California",
"CO" => "Colorado",
"CT" => "Connecticut",
"DC" => "District of Columbia",
"DE" => "Delaware",
"FL" => "Florida",
"GA" => "Georgia",
"GU" => "Guam",
"HI" => "Hawaii",
"IA" => "Iowa",
"ID" => "Idaho",
"IL" => "Illinois",
"IN" => "Indiana",
"KS" => "Kansas",
"KY" => "Kentucky",
"LA" => "Louisiana",
"MA" => "Massachusetts",
"MD" => "Maryland",
"ME" => "Maine",
"MI" => "Michigan",
"MN" => "Minnesota",
"MO" => "Missouri",
"MS" => "Mississippi",
"MT" => "Montana",
"NC" => "North Carolina",
"ND" => "North Dakota",
"NE" => "Nebraska",
"NH" => "New Hampshire",
"NJ" => "New Jersey",
"NM" => "New Mexico",
"NV" => "Nevada",
"NY" => "New York",
"OH" => "Ohio",
"OK" => "Oklahoma",
"OR" => "Oregon",
"PA" => "Pennsylvania",
"PR" => "Puerto Rico",
"RI" => "Rhode Island",
"SC" => "South Carolina",
"SD" => "South Dakota",
"TN" => "Tennessee",
"TX" => "Texas",
"UT" => "Utah",
"VA" => "Virginia",
"VI" => "Virgin Islands",
"VT" => "Vermont",
"WA" => "Washington",
"WI" => "Wisconsin",
"WV" => "West Virginia",
"WY" => "Wyoming"
}.freeze
end
RSpec.describe UsState do
it "is valid with valid abbreviation" do
expect_valid_dc_instance(described_class.new("DC"))
expect_valid_md_instance(described_class.new("md"))
expect_valid_va_instance(described_class.new(:va))
expect(described_class.new(" vA")).not_to be_valid
end
it "is valid with valid state name" do
expect_valid_dc_instance(described_class.new("District of Columbia"))
expect(described_class.new("District Of Columbia")).not_to be_valid
expect(described_class.new("district of columbia")).not_to be_valid
end
context "when input is nil" do
it "has nil name and nil abbreviation" do
instance = described_class.new(nil)
expect(instance.name).to be_nil
expect(instance.abbreviation).to be_nil
end
end
private
def expect_valid_dc_instance(instance)
expect(instance).to be_valid
expect(instance.name).to eq("District of Columbia")
expect(instance.abbreviation).to eq("DC")
end
def expect_valid_md_instance(instance)
expect(instance).to be_valid
expect(instance.name).to eq("Maryland")
expect(instance.abbreviation).to eq("MD")
end
def expect_valid_va_instance(instance)
expect(instance).to be_valid
expect(instance.name).to eq("Virginia")
expect(instance.abbreviation).to eq("VA")
end
end