class WxAlert::Alert

Class containing an individual alert. Each alert has 3 variables: alert - The hash containing the alert itself fixed - If the alert has been fixed and processed full - If the alert is the complete CAP alert versus

what's pulled from the index.

TODO: full - If the alert is the complete CAP alert

Constants

HVTEC_ERR

Empty H-VETCS appear as this in the index

NONE

String constants

Attributes

alert[R]

Class getters

fixed[R]

Class getters

full[R]

Class getters

Public Class Methods

hash_str_key_to_sym(hash) click to toggle source

Takes a hash and converts each string key into a symbol. Since some values in an alert hash are hashes themselves, this method will convert the keys of all sub hashes as well as the parent hash.

# File lib/WxAlert/alert.rb, line 52
def self.hash_str_key_to_sym(hash)
  # Map through each hash
  hash.map do |key, value|
    # If the value is a hash, recurse through it
    if value.is_a? Hash
      # Recurse and replace sub hashes
      temp = hash_str_key_to_sym(value)
      value.replace(temp.pop)
    end
    # Convert each key to a symbol
    {str_to_sym(key) => value}
  end
end
new(alert, fixed = false) click to toggle source

Sets up new alert taking two parameters, a hash containing a raw alert and a boolean if the alert has already been fixed.

# File lib/WxAlert/alert.rb, line 24
def initialize(alert, fixed = false)
  @alert = alert
  @fixed = fixed
  @full  = false
  fix unless fixed
  self
end
str_to_sym(str) click to toggle source

Extremely clever function that converts strings to symbols for the purpose of making raw NWS alerts into slightly prettier Ruby hashes.

# File lib/WxAlert/alert.rb, line 35
def self.str_to_sym(str)
  # Make sure str is actually a string and symbol-able
  # This is mostly to catch keys that are already symbols
  if str.respond_to?('gsub') && str.respond_to?('to_sym')
    # EXTREMELY CLEVER PROGRAMMING (please hire me)
    str.gsub(/\s+/, '_').downcase.to_sym
  else
    # Return whatever was passed in
    str
  end
end

Public Instance Methods

fix() click to toggle source

Fix the ugly, raw alert. Turns keys to symbols, and extracts various data elements. TODO: Deal with this one-level-nested hashes. Probs flatten them.

# File lib/WxAlert/alert.rb, line 77
def fix
  # Don't fix a fixed alert
  return @alert if @fixed

  # Change keys to symbols and flatten the hash.
  @alert.replace(
      Alert.hash_str_key_to_sym(@alert).reduce({}, :merge))

  # Run the fixing methods if a valid alert.
  apply_fixes unless not_alert?
  @fixed = true

  # Return the alert hash
  @alert
end
match?(hash_key, value) click to toggle source

Takes a hash key and value, returns true if the Alert's alert hash has a matching key and value. If the key corresponds to an array, if any element in the array matches the value. TODO: Check sub hashes

# File lib/WxAlert/alert.rb, line 98
def match?(hash_key, value)
  # real_value = @alert[hash_key]
  # Check the contents of any arrays
  if @alert[hash_key].is_a? Array
    @alert[hash_key].map { |str| str.include? value }.include? true
  else
    @alert[hash_key].include? value
  end
end
not_alert?() click to toggle source

Return true if the Alert object is actually not an alert. That is, it is the no alerts message from NWS.

# File lib/WxAlert/alert.rb, line 69
def not_alert?
  true if @alert[:title] == 'There are no active watches'\
                            ', warnings or advisories'
end
retrieve_full() click to toggle source

Retrieve the entire CAP alert. Specifically retrieves the entire description text, and the timemotloc code. TODO: Do something else with the timemotloc code TODO: Get Instructions

# File lib/WxAlert/alert.rb, line 113
def retrieve_full
  return self if @full || not_alert?
  full = Downloader.get(@alert[:id])['alert']['info']
  @alert[:summary] = full['description']

  @alert[:timemotloc] = full['parameter'].last[:value]

  @alert[:timemotloc] ||= NONE

  @full = true
  self
end

Protected Instance Methods

apply_fixes() click to toggle source

Clever way to appease Rubocop and take advantage of a neat Ruby feature. Also easy to add more stuff.

# File lib/WxAlert/alert.rb, line 130
def apply_fixes
  fix_methods = [:fix_vtec, :fix_geocode, :fix_polygon,
                 :fix_areadesc, :fix_nested_hashes]
  fix_methods.each { |method| send(method) }
  # Add the empty timemotloc key
  @alert[:timemotloc] = NONE
end
fix_areadesc() click to toggle source

Split up human readable location descriptions into an array.

# File lib/WxAlert/alert.rb, line 262
def fix_areadesc
  @alert[:areadesc] = @alert[:areadesc].split(/;\s/)
end
fix_fips(geocodes) click to toggle source

Split up the FIPS codes and put them in an array.

# File lib/WxAlert/alert.rb, line 221
def fix_fips(geocodes)
  if geocodes.respond_to?('split')
    @alert[:fips] = geocodes.split
  else
    @alert[:fips] = [NONE]
  end
end
fix_geocode() click to toggle source

Clean up the geocodes, that is, split up the FIPS and UGC codes, and put them into array.

# File lib/WxAlert/alert.rb, line 204
def fix_geocode
  bad_geocodes = @alert[:geocode][:value]

  # Some alerts don't have geocodes
  if bad_geocodes.is_a?(Array) && bad_geocodes.length == 2
    fix_fips(bad_geocodes[0])
    fix_ugc(bad_geocodes[1])
  else
    return
  end

  # Get rid of the old geocode key
  @alert.delete(:geocode)
end
fix_nested_hashes() click to toggle source

Flatten unneeded sub-hashes, that is, keys that map to a hash with exactly one key-value pair.

# File lib/WxAlert/alert.rb, line 140
def fix_nested_hashes
  @alert.each do |key, val|
    if val.is_a?(Hash) && val.length == 1
      @alert[key] = val.first[1]
    end
  end
end
fix_polygon() click to toggle source

Split up each set of coordinates and put each set as a two element array, and each of those arrays in an array. TODO: Convert the number string to a float

# File lib/WxAlert/alert.rb, line 246
def fix_polygon
  polygon = @alert[:polygon]

  # If there is a polygon, convert it to an
  # array of coordinates.
  if polygon.respond_to?('split')
    @alert[:polygon] = polygon.split.map do |pnt|
      pnt.split(',').map { |coord| coord.to_f }
    end
  else
    @alert[:polygon] = NONE
  end
end
fix_ugc(geocodes) click to toggle source

Split up the UGC codes and put them in an array. NOTE: As far as I can tell, in the indexes every UGC code is listed, and are not abbreviated like in 'full' CAP alerts.

# File lib/WxAlert/alert.rb, line 234
def fix_ugc(geocodes)
  if geocodes.respond_to?('split')
    @alert[:ugc] = geocodes.split
  else
    @alert[:ugc] = [NONE]
  end
end
fix_vtec() click to toggle source

VTECs come in funky. Sometimes only one is present, when both are, they are separated by a newline.

# File lib/WxAlert/alert.rb, line 150
def fix_vtec
  # Split up the VTECs, which come in the specified location
  # for some reason I'm not sure of.
  if @alert[:parameter][:value].respond_to?('length')
    # Split up the VTECs
    pvtec, hvtec = split_vtec @alert[:parameter][:value]
  else
    # If there isn't any VTECs assign NONE to both
    pvtec, hvtec = NONE, NONE
  end

  # By the way, RuboCop needs to just chill the hell out.
  # When I clean this up it is getting configured SO HARD

  @alert[:pvtec], @alert[:hvtec] = pvtec.to_s, hvtec.to_s

  # Delete the weirdly named ex-home of the VTEC(s)
  @alert.delete(:parameter)
end
split_vtec(vtec) click to toggle source

Split up the raw VTEC string depending on which VTECs are present. Takes the raw vtec string returns pvtec, hvtec

# File lib/WxAlert/alert.rb, line 174
def split_vtec(vtec)
  # Get rid of the newline, if it exists.
  vtec = vtec.split("\n")
  vtec_str = vtec.join

  # I'LL TAKE THE CASE!
  # Assigns VTECs depending on which exist.
  case vtec_str.length
    when 48
      # P-VTECs are 48 characters
      return vtec_str, NONE
    when 54
      # H-VTECs are 54 characters
      # Change any 'error' hvtecs to NONE
      (vtec_str == HVTEC_ERR) ? hvtec = NONE : hvtec = vtec_str
      return NONE, hvtec
    else
      # Both codes exist, or something is super borked.
      # pvtec, hvtec
      if vtec.length == 2
        return vtec[0], vtec[1]
      else
        return NONE, NONE
      end
  end
end