def self.parse(raw)
m = METAR.new
m.raw = raw
groups = raw.split
m.speci = false
case g = groups.shift
when 'METAR'
g = groups.shift
when 'SPECI'
m.speci = true
g = groups.shift
end
if g =~ /^([a-zA-Z0-9]{4})$/
m.station = $1
g = groups.shift
else
raise ParseError, "Invalid Station Identifier '#{g}'"
end
if g =~ /^(\d\d)(\d\d)(\d\d)Z$/
m.time = Time.parse(g)
g = groups.shift
else
raise ParseError, "Invalid Date and Time '#{g}'"
end
if g == 'AUTO'
m.auto = true
g = groups.shift
elsif g == 'COR'
m.cor = true
g = groups.shift
end
if g =~ /^((\d\d\d)|VRB)(\d\d\d?)(G(\d\d\d?))?(KT|KMH|MPS)$/
if groups.first =~ /^(\d\d\d)V(\d\d\d)$/
g = g + ' ' + groups.shift
end
m.wind = Wind.new(g)
g = groups.shift
end
if g =~ /^\d+$/ and groups.first =~ /^M?\d+\/\d+SM$/
m.visibility = Visibility.new(g+' '+groups.shift)
g = groups.shift
elsif g =~ /^M?\d+(\/\d+)?SM$/
m.visibility = Visibility.new(g)
g = groups.shift
end
m.rvr = []
while g =~ /^R(\d+[LCR]?)\/([PM]?)(\d+)(V([PM]?)(\d+))?FT$/
m.rvr.push RunwayVisualRange.new(g)
g = groups.shift
end
m.weather = []
while g =~ /^([-+]|VC)?(MI|PR|BC|DR|BL|SH|TS|FZ|DZ|RA|SN|SG|IC|PE|PL|GR|GS|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS)+$/
m.weather.push PresentWeather.new(g)
g = groups.shift
end
m.sky = []
while g =~ /^(SKC|CLR)|(VV|FEW|SCT|BKN|OVC)/
m.sky.push Sky.new(g)
g = groups.shift
end
if g =~ /^(M?)(\d\d)\/((M?)(\d\d))?$/
t = $2.to_i
t = -t if $1 == 'M'
m.temp = "#{t} tempC".unit
if $3
d = $5.to_i
d = -d if $4 == 'M'
m.dewpoint = "#{d} tempC".unit
end
g = groups.shift
end
if g =~ /^A(\d\d\d\d)$/
m.altimiter = "#{$1.to_f / 100} inHg".unit
g = groups.shift
end
if g == 'RMK'
m.rmk = groups.join(' ')
groups = []
end
unless groups.empty?
raise ParseError, "Leftovers after parsing: #{groups.join(' ')}"
end
return m
end