lib/eew_parser.rb in eew_parser-0.1.6 vs lib/eew_parser.rb in eew_parser-0.1.7

- old
+ new

@@ -2,12 +2,11 @@ require_relative "epicenter_code" require_relative "area_code" # 緊急地震速報パーサ -# Author:: Glass_saga -# License:: NYSL Version 0.9982 +# Author:: mmasaki # # 高度利用者向け緊急地震速報コード電文フォーマットを扱う為のライブラリです。 # http://eew.mizar.jp/excodeformat を元に作成しました。 # # str = <<EOS @@ -28,20 +27,25 @@ # 引数には緊急地震速報の電文を与えます。 def initialize(str) raise ArgumentError unless str.is_a?(String) @fastcast = str.dup @fastcast.freeze - raise Error, "電文の形式が不正です" if @fastcast.size < 135 + raise Error, "電文の形式が不正です" if @fastcast.bytesize < 135 end attr_reader :fastcast # initializeに与えられた電文を返します。 def to_s - @fastcast + @fastcast.dup end + # 電文のサイズを返します。 + def size + @fastcast.bytesize + end + # 緊急地震速報の内容をテキストで出力します。 def print str = <<-EOS 電文種別: #{self.type} 発信官署: #{self.from} @@ -92,20 +96,28 @@ hash[attribute] = __send__(attribute) end return hash end + # 正しい電文であるかを返します + def verify + Attributes.each do |attribute| + __send__(attribute) + end + return true + end + def inspect - "#<EEWParser:#{id}>" + "#<EEWParser:#{id} (第#{number}報) #{epicenter} #{seismic_intensity}>" end def ==(other) fastcast == other.fastcast end def <=>(other) - Integer(id) <=> Integer(id) + __id__ <=> other.__id__ end # 電文種別コード def type case @fastcast[0, 2] @@ -160,20 +172,33 @@ else raise Error, "電文の形式が不正です(識別符)" end end + # 訓練かどうか + def drill? + case @fastcast[6, 2] + when "00", "10", "20" + return false + when "01", "11", "30" + return true + else + raise Error, "電文の形式が不正です(識別符)" + end + end + # 電文の発表時刻のTimeオブジェクトを返します。 def report_time Time.local("20" + @fastcast[9, 2], @fastcast[11, 2], @fastcast[13, 2], @fastcast[15, 2], @fastcast[17, 2], @fastcast[19, 2]) end # 電文がこの電文を含め何通あるか(Integer) def number_of_telegram number_of_telegram = @fastcast[23] - raise Error, "電文の形式が不正です" if number_of_telegram =~ /[^\d]/ - number_of_telegram.to_i + return Integer(number_of_telegram, 10) + rescue ArgumentError + raise Error, "電文の形式が不正です" end # コードが続くかどうか def continue? case @fastcast[24] @@ -192,14 +217,20 @@ end # 地震識別番号(String) def id id = @fastcast[41, 14] - raise Error, "電文の形式が不正です(地震識別番号)" if id =~ /[^\d]/ - id + Integer(id, 10) # verify + return id + rescue ArgumentError + raise Error, "電文の形式が不正です(地震識別番号: #{id})" end + def __id__ + id + number.to_s + end + # 発表状況(訂正等)の指示 def status case @fastcast[59] when "0" "通常発表" @@ -216,10 +247,16 @@ else raise Error, "電文の形式が不正です" end end + # 第1報であればtrueを、そうでなければfalseを返します。 + def first? + return true if self.number == 1 + return false + end + # 最終報であればtrueを、そうでなければfalseを返します。 def final? case @fastcast[59] when "9" true @@ -231,56 +268,63 @@ end # 発表する高度利用者向け緊急地震速報の番号(地震単位での通番)(Integer) def number number = @fastcast[60, 2] - raise Error, "電文の形式が不正です(高度利用者向け緊急地震速報の番号)" if number =~ /[^\d]/ - number.to_i + return Integer(number, 10) + rescue ArgumentError + raise Error, "電文の形式が不正です(高度利用者向け緊急地震速報の番号)" end alias :revision :number # 震央の名称 def epicenter - key = @fastcast[86, 3] - raise Error, "電文の形式が不正です(震央の名称)" if key =~ /[^\d]/ - EpicenterCode[key.to_i] + code = @fastcast[86, 3] + code = Integer(code, 10) + EpicenterCode.fetch(code) + rescue KeyError + raise Error, "電文の形式が不正です(震央地名コード: #{code})" + rescue ArgumentError + raise Error, "電文の形式が不正です(震央の名称)" end # 震央の位置 def position position = @fastcast[90, 10] if position == "//// /////" "不明又は未設定" else - raise Error, "電文の形式が不正です(震央の位置)" if position =~ /[^\d|\s|N|E]/ + raise Error, "電文の形式が不正です(震央の位置)" unless position.match(/N\d{3} E\d{4}/) position.insert(3, ".").insert(10, ".") end end # 震源の深さ(単位 km) def depth depth = @fastcast[101, 3] if depth == "///" - "不明又は未設定" + return "不明又は未設定" else - raise Error, "電文の形式が不正です(震源の深さ)" if depth =~ /[^\d]/ - depth.to_i + return Integer(depth, 10) end + rescue ArgumentError + raise Error, "電文の形式が不正です(震源の深さ)" end # マグニチュード # マグニチュードが不明又は未設定である場合は"不明又は未設定"を返します。 # そうでなければ、マグニチュードをFloatで返します。 def magnitude magnitude = @fastcast[105, 2] if magnitude == "//" - "不明又は未設定" + return "不明又は未設定" else - raise Error, "電文の形式が不正です(マグニチュード)" if magnitude =~ /[^\d]/ - (magnitude[0] + "." + magnitude[1]).to_f + return Float(magnitude[0] + "." + magnitude[1]) end + rescue ArgumentError + raise Error, "電文の形式が不正です(マグニチュード)" end # 電文フォーマットの震度を文字列に変換 def to_seismic_intensity(str) case str @@ -310,12 +354,10 @@ end # 最大予測震度 def seismic_intensity to_seismic_intensity(@fastcast[108, 2]) - rescue Error - raise Error, "電文の形式が不正です(最大予測震度)" end # 震央の確からしさ def probability_of_position case @fastcast[113] @@ -484,10 +526,20 @@ else raise Error, "電文の形式が不正です(最大予測震度の変化)" end end + # 最大予測震度に変化があったかどうか + def changed? + case @fastcast[129] + when "0", "3".."9", "/" + return false + when "1", "2" + return true + end + end + # 最大予測震度の変化の理由 def reason_of_change case @fastcast[130] when "0" "変化無し" @@ -506,10 +558,19 @@ else raise Error, "電文の形式が不正です(最大予測震度の変化の理由)" end end + # EBIを含むかどうか + def has_ebi? + if @fastcast[135, 3] == "EBI" + return true + else + return false + end + end + # 地域毎の警報の判別、最大予測震度及び主要動到達予測時刻 # EBIがあればHashを格納したArrayを、なければ空のArrayを返します。Hashに格納されるkeyとvalueはそれぞれ次のようになっています。 # :area_name 地域名称 # :intensity 最大予測震度 # :arrival_time 予想到達時刻のTimeオブジェクト。既に到達している場合はnil @@ -517,10 +578,10 @@ # :arrival 既に到達していればtrue、そうでなければfalse、電文にこの項目が設定されていなければnil def ebi data = [] return data unless @fastcast[135, 3] == "EBI" i = 139 - while i + 20 < @fastcast.size + while i + 20 < @fastcast.bytesize local = {} local[:area_code] = @fastcast[i, 3].to_i local[:area_name] = AreaCode[local[:area_code]] # 地域名称 raise Error, "電文の形式が不正でです(地域名称[EBI])" unless local[:area_name] if @fastcast[i+7, 2] == "//"