jma_feed 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jma_feed/atom/eqvol.rb +7 -0
  3. data/lib/jma_feed/{api → atom}/extra.rb +1 -1
  4. data/lib/jma_feed/atom/other.rb +7 -0
  5. data/lib/jma_feed/{api → atom}/regular.rb +1 -1
  6. data/lib/jma_feed/{api.rb → atom.rb} +5 -1
  7. data/lib/jma_feed/entity/weather_alert/metrics_item.rb +14 -0
  8. data/lib/jma_feed/entity/weather_alert.rb +177 -0
  9. data/lib/jma_feed/node/base_node.rb +4 -0
  10. data/lib/jma_feed/report.rb +7 -0
  11. data/lib/jma_feed/report_entry/jmx/discharge.rb +4 -0
  12. data/lib/jma_feed/report_entry/jmx/earthquake.rb +22 -0
  13. data/lib/jma_feed/report_entry/jmx/earthquake_intensity.rb +14 -0
  14. data/lib/jma_feed/report_entry/jmx/humidity.rb +20 -0
  15. data/lib/jma_feed/report_entry/jmx/precipitation.rb +13 -0
  16. data/lib/jma_feed/report_entry/jmx/significancy.rb +14 -0
  17. data/lib/jma_feed/report_entry/jmx/snow_fall_depth.rb +20 -0
  18. data/lib/jma_feed/report_entry/jmx/tidal_level.rb +20 -0
  19. data/lib/jma_feed/report_entry/jmx/time_define.rb +18 -0
  20. data/lib/jma_feed/report_entry/jmx/visibility.rb +20 -0
  21. data/lib/jma_feed/report_entry/jmx/water_level.rb +4 -0
  22. data/lib/jma_feed/report_entry/jmx/wave_height.rb +20 -0
  23. data/lib/jma_feed/report_entry/jmx/wind_direction.rb +20 -0
  24. data/lib/jma_feed/report_entry/jmx/wind_speed.rb +20 -0
  25. data/lib/jma_feed/report_entry/vphw50.rb +4 -4
  26. data/lib/jma_feed/report_entry/vprn50.rb +5 -4
  27. data/lib/jma_feed/report_entry/vpww54.rb +220 -31
  28. data/lib/jma_feed/report_entry/vxse53.rb +135 -0
  29. data/lib/jma_feed/report_entry.rb +19 -2
  30. data/lib/jma_feed/result.rb +4 -0
  31. data/lib/jma_feed/result_doc.rb +6 -2
  32. data/lib/jma_feed/result_entry.rb +24 -1
  33. data/lib/jma_feed/version.rb +1 -1
  34. data/lib/jma_feed.rb +7 -3
  35. metadata +24 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c76dfa5b24cec264aa047de3a21871a1cce3fcf7bee5908a88ecd0029d8fda1
4
- data.tar.gz: 10abdfb01733d13e2d733a6f2499e6a2a614f3fb181797852602db2f5b45441a
3
+ metadata.gz: 5f2d20e3b5f31fc0cb5726f48dceb280e6b49110da4dc110ec3df67b888cf4ad
4
+ data.tar.gz: 188051f02027907aec84fd0e8f58c1223daa46b4c4da6b3074f87252837cefd8
5
5
  SHA512:
6
- metadata.gz: 31aa0529c9797ef626849ecf3392dbea29a449917751f142c765dc0818b4f73e35642d4e481d9f05fd92acf8ec23ef2d51a333f8c6d9cdc7af2a1b92ce2affc7
7
- data.tar.gz: ca936a1a99345e281a278c8aa1d234397ca90c600c2a4e3efc500d2bcdb463276ee28faac9bd45ba5d5bbd0dc4fc67773c0148f620635023517b82784bcce3cf
6
+ metadata.gz: 05ca0c27158b6111371e3b2111f8d2041f77ad0f8708828216bc569745ccfd0493da0d94a30cb83ae8faba62216cc2d044ce989b67ff92b7b6393674f9a5e4e3
7
+ data.tar.gz: 94fd7457b4471845cff5f3d9542344da3de9962e8376581770d06562d304c5f6c06b857eef70aa938fd2a0ab333e42326f293df2d03b5390cf38b9def8b03026
@@ -0,0 +1,7 @@
1
+ class JMAFeed::Eqvol
2
+ include JMAFeed::Atom
3
+
4
+ def feed_type
5
+ :eqvol
6
+ end
7
+ end
@@ -1,5 +1,5 @@
1
1
  class JMAFeed::Extra
2
- include JMAFeed::Api
2
+ include JMAFeed::Atom
3
3
 
4
4
  def feed_type
5
5
  :extra
@@ -0,0 +1,7 @@
1
+ class JMAFeed::Other
2
+ include JMAFeed::Atom
3
+
4
+ def feed_type
5
+ :other
6
+ end
7
+ end
@@ -1,5 +1,5 @@
1
1
  class JMAFeed::Regular
2
- include JMAFeed::Api
2
+ include JMAFeed::Atom
3
3
 
4
4
  def feed_type
5
5
  :regular
@@ -1,6 +1,6 @@
1
1
  require "net/http"
2
2
 
3
- module JMAFeed::Api
3
+ module JMAFeed::Atom
4
4
 
5
5
  def self.type(feed_type, **args)
6
6
  feed_type = feed_type.to_sym
@@ -8,6 +8,10 @@ module JMAFeed::Api
8
8
  JMAFeed::Regular.new(**args)
9
9
  elsif feed_type == :extra
10
10
  JMAFeed::Extra.new(**args)
11
+ elsif feed_type == :eqvol
12
+ JMAFeed::Eqvol.new(**args)
13
+ elsif feed_type == :other
14
+ JMAFeed::Other.new(**args)
11
15
  else
12
16
  raise "feed_type=#{feed_type} not supported"
13
17
  end
@@ -0,0 +1,14 @@
1
+ class JMAFeed::WeatherAlert::MetricsItem < Struct.new(
2
+ :name, :value, :description, :time_define,
3
+ keyword_init: true
4
+ )
5
+
6
+ def to_h
7
+ {
8
+ name: name,
9
+ value: value,
10
+ description: description,
11
+ time_define: time_define.to_h,
12
+ }
13
+ end
14
+ end
@@ -161,6 +161,171 @@ class JMAFeed::WeatherAlert < Struct.new(:code, :name, :risk_level, :cluster, ke
161
161
  },
162
162
  }
163
163
 
164
+ # 気象警報・注意(H27)_解説資料.pdf > 別表4
165
+ METRICS = {
166
+ storm_metrics: {
167
+ "風危険度" => {
168
+ name: :significancy,
169
+ property_type: "危険度",
170
+ },
171
+ "風向" => {
172
+ name: :wind_direction,
173
+ property_type: "風",
174
+ },
175
+ "最大風速" => {
176
+ name: :wind_speed,
177
+ property_type: "風",
178
+ },
179
+ },
180
+ rain_metrics: {
181
+ "土砂災害危険度" => {
182
+ name: :significancy,
183
+ property_type: "危険度",
184
+ },
185
+ "浸水害危険度" => {
186
+ name: :significancy,
187
+ property_type: "危険度",
188
+ },
189
+ "1時間最大雨量" => {
190
+ name: :precipitation,
191
+ property_type: "雨",
192
+ },
193
+ "3時間最大雨量" => {
194
+ name: :precipitation,
195
+ property_type: "雨",
196
+ },
197
+ },
198
+ flood_metrics: {
199
+ "洪水害危険度" => {
200
+ name: :significancy,
201
+ property_type: "危険度",
202
+ },
203
+ },
204
+ snow_metrics: {
205
+ "雪危険度" => {
206
+ name: :significancy,
207
+ property_type: "危険度",
208
+ },
209
+ "6時間最大降雪量" => {
210
+ name: :snow_fall_depth,
211
+ property_type: "雪",
212
+ },
213
+ "12時間最大降雪量" => {
214
+ name: :snow_fall_depth,
215
+ property_type: "雪",
216
+ },
217
+ "24時間最大降雪量" => {
218
+ name: :snow_fall_depth,
219
+ property_type: "雪",
220
+ },
221
+ },
222
+ wave_metrics: {
223
+ "波危険度" => {
224
+ name: :significancy,
225
+ property_type: "危険度",
226
+ },
227
+ "波高" => {
228
+ name: :wave_height,
229
+ property_type: "波",
230
+ },
231
+ },
232
+ tide_metrics: {
233
+ "高潮危険度" => {
234
+ name: :significancy,
235
+ property_type: "危険度",
236
+ },
237
+ "最高潮位" => {
238
+ name: :tidal_level,
239
+ property_type: "高",
240
+ },
241
+ },
242
+ thunder_metrics: {
243
+ "雷危険度" => {
244
+ name: :significancy,
245
+ property_type: "危険度",
246
+ },
247
+ },
248
+ snow_melting_metrics: {
249
+ "融雪危険度" => {
250
+ name: :significancy,
251
+ property_type: "危険度",
252
+ },
253
+ },
254
+ fog_metrics: {
255
+ "濃霧危険度" => {
256
+ name: :significancy,
257
+ property_type: "危険度",
258
+ },
259
+ "視程" => {
260
+ name: :visibility,
261
+ property_type: "濃霧",
262
+ },
263
+ },
264
+ dry_air_metrics: {
265
+ "乾燥危険度" => {
266
+ name: :significancy,
267
+ property_type: "危険度",
268
+ },
269
+ "実効湿度" => {
270
+ name: :humidity,
271
+ property_type: "乾燥",
272
+ },
273
+ "最小湿度" => {
274
+ name: :humidity,
275
+ property_type: "乾燥",
276
+ },
277
+ },
278
+ avalanche_metrics: {
279
+ "なだれ危険度" => {
280
+ name: :significancy,
281
+ property_type: "危険度",
282
+ },
283
+ },
284
+ low_temperature_metrics: {
285
+ "低温危険度" => {
286
+ name: :significancy,
287
+ property_type: "危険度",
288
+ },
289
+ },
290
+ frost_metrics: {
291
+ "霜危険度" => {
292
+ name: :significancy,
293
+ property_type: "危険度",
294
+ },
295
+ },
296
+ ice_accretion_metrics: {
297
+ "着氷危険度" => {
298
+ name: :significancy,
299
+ property_type: "危険度",
300
+ },
301
+ },
302
+ snow_accretion_metrics: {
303
+ "着雪危険度" => {
304
+ name: :significancy,
305
+ property_type: "危険度",
306
+ },
307
+ },
308
+ }
309
+
310
+ CLUSTER_METRICS = {
311
+ storm: METRICS[:storm_metrics],
312
+ snowstorm: METRICS[:storm_metrics],
313
+ heavy_rain: METRICS[:rain_metrics],
314
+ flood: METRICS[:flood_metrics],
315
+ heavy_snow: METRICS[:snow_metrics],
316
+ high_wave: METRICS[:wave_metrics],
317
+ storm_surge: METRICS[:tide_metrics],
318
+ thunderstorm: METRICS[:thunder_metrics],
319
+ snow_melting: METRICS[:snow_melting_metrics],
320
+ dense_fog: METRICS[:fog_metrics],
321
+ dry_air: METRICS[:dry_air_metrics],
322
+ avalanche: METRICS[:avalanche_metrics],
323
+ low_temperature: METRICS[:low_temperature_metrics],
324
+ frost: METRICS[:frost_metrics],
325
+ ice_accretion: METRICS[:ice_accretion_metrics],
326
+ snow_accretion: METRICS[:snow_accretion_metrics],
327
+ }
328
+
164
329
  def self.clusters
165
330
  all.group_by(&:cluster)
166
331
  end
@@ -168,4 +333,16 @@ class JMAFeed::WeatherAlert < Struct.new(:code, :name, :risk_level, :cluster, ke
168
333
  def self.all
169
334
  @all ||= LIST.map{|k,v| new(v.merge(code: k.to_s))}
170
335
  end
336
+
337
+ def self.metrics_properties
338
+ METRICS.values.reduce(&:merge)
339
+ end
340
+
341
+ def self.metrics_components
342
+ metrics_properties.values.uniq
343
+ end
344
+
345
+ def metrics
346
+ CLUSTER_METRICS[cluster.to_sym] || {}
347
+ end
171
348
  end
@@ -0,0 +1,4 @@
1
+ class JMAFeed::BaseNode < Giri::BaseNode
2
+ self.with_name_default_for_node = :camelize
3
+ self.with_name_default_for_attribute = :lower_camelcase
4
+ end
@@ -95,4 +95,11 @@ class JMAFeed::Report < Struct.new(
95
95
  def has_kind?(k)
96
96
  Array(kind).include?(k)
97
97
  end
98
+
99
+ def report_entry_class
100
+ return nil unless code_represented
101
+ JMAFeed.const_get(code_represented)
102
+ rescue NameError => e
103
+ JMAFeed::ReportEntry
104
+ end
98
105
  end
@@ -4,4 +4,8 @@ class JMAFeed::JMX::Discharge < Giri::TextNodeBigDecimal
4
4
  xml_attribute :ref_id, with_name: "refID"
5
5
  xml_attribute :condition
6
6
  xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
7
11
  end
@@ -0,0 +1,22 @@
1
+ # jmx_eb
2
+ class JMAFeed::JMX::Earthquake < Giri::BaseNode
3
+ date_time_node :origin_time
4
+ date_time_node :arrival_time
5
+
6
+ xml_node :hypocenter do
7
+ xml_node :area do
8
+ text_node :name
9
+ text_node :code do
10
+ xml_attribute :type
11
+ end
12
+ text_node :coordinate do
13
+ text_node :description
14
+ text_node :datum
15
+ end
16
+ end
17
+ end
18
+ big_decimal_node :magnitude do
19
+ xml_attribute :type
20
+ xml_attribute :description
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ class JMAFeed::JMX::EarthquakeIntensity < Giri::TextNodeString
2
+ # self:
3
+ # 1, 2, 3, 4, 5-, 5+, 6-, 6+, 7, 震度5弱以上未入電
4
+
5
+ def intensity
6
+ value = self.sub(/\-\z/, '').sub(/\+\z/, '.5').to_f
7
+ value > 0 ? value : nil
8
+ end
9
+
10
+ def title
11
+ return self unless intensity
12
+ "震度" + self.sub(/\-\z/, '弱').sub(/\+\z/, '強')
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ class JMAFeed::JMX::Humidity < Giri::TextNodeInteger
2
+ xml_attribute :type
3
+ xml_attribute :unit
4
+ xml_attribute :ref_id, with_name: "refID"
5
+ # xml_attribute :condition
6
+ xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
11
+
12
+ def metrics_item
13
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
14
+ name: type,
15
+ value: self,
16
+ description: description,
17
+ time_define: time_define,
18
+ )
19
+ end
20
+ end
@@ -4,4 +4,17 @@ class JMAFeed::JMX::Precipitation < Giri::TextNodeInteger
4
4
  xml_attribute :ref_id, with_name: "refID"
5
5
  xml_attribute :condition
6
6
  xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
11
+
12
+ def metrics_item
13
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
14
+ name: type,
15
+ value: self,
16
+ description: description,
17
+ time_define: time_define,
18
+ )
19
+ end
7
20
  end
@@ -1,7 +1,21 @@
1
1
  # jmx_mete
2
2
  class JMAFeed::JMX::Significancy < Giri::BaseNode
3
3
  xml_attribute :type
4
+ xml_attribute :ref_id, with_name: "refID"
4
5
  text_node :name
5
6
  text_node :code
6
7
  text_node :condition
8
+
9
+ def time_define
10
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
11
+ end
12
+
13
+ def metrics_item
14
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
15
+ name: type,
16
+ value: code,
17
+ description: name,
18
+ time_define: time_define,
19
+ )
20
+ end
7
21
  end
@@ -0,0 +1,20 @@
1
+ class JMAFeed::JMX::SnowFallDepth < Giri::TextNodeInteger
2
+ xml_attribute :type
3
+ xml_attribute :unit
4
+ xml_attribute :ref_id, with_name: "refID"
5
+ # xml_attribute :condition
6
+ xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
11
+
12
+ def metrics_item
13
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
14
+ name: type,
15
+ value: self,
16
+ description: description,
17
+ time_define: time_define,
18
+ )
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ class JMAFeed::JMX::TidalLevel < Giri::TextNodeBigDecimal
2
+ xml_attribute :type
3
+ xml_attribute :unit
4
+ xml_attribute :ref_id, with_name: "refID"
5
+ # xml_attribute :condition
6
+ xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
11
+
12
+ def metrics_item
13
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
14
+ name: type,
15
+ value: self,
16
+ description: description,
17
+ time_define: time_define,
18
+ )
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ class JMAFeed::JMX::TimeDefine < Giri::BaseNode
2
+ xml_attribute :time_id, with_name: :lower_camelcase
3
+ date_time_node :date_time
4
+ duration_node :duration
5
+ text_node :name
6
+
7
+ def start_at
8
+ date_time
9
+ end
10
+
11
+ def end_at
12
+ start_at + duration.duration_time
13
+ end
14
+
15
+ def to_h
16
+ {name: name, start_at: start_at, end_at: end_at, duration: duration}
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ class JMAFeed::JMX::Visibility < Giri::TextNodeInteger
2
+ xml_attribute :type
3
+ xml_attribute :unit
4
+ xml_attribute :ref_id, with_name: "refID"
5
+ xml_attribute :condition
6
+ xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
11
+
12
+ def metrics_item
13
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
14
+ name: type,
15
+ value: self,
16
+ description: description,
17
+ time_define: time_define,
18
+ )
19
+ end
20
+ end
@@ -4,4 +4,8 @@ class JMAFeed::JMX::WaterLevel < Giri::TextNodeBigDecimal
4
4
  xml_attribute :ref_id, with_name: "refID"
5
5
  xml_attribute :condition
6
6
  xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
7
11
  end
@@ -0,0 +1,20 @@
1
+ class JMAFeed::JMX::WaveHeight < Giri::TextNodeBigDecimal
2
+ xml_attribute :type
3
+ xml_attribute :unit
4
+ xml_attribute :ref_id, with_name: "refID"
5
+ # xml_attribute :condition
6
+ xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
11
+
12
+ def metrics_item
13
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
14
+ name: type,
15
+ value: self,
16
+ description: description,
17
+ time_define: time_define,
18
+ )
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ class JMAFeed::JMX::WindDirection < Giri::TextNodeString
2
+ xml_attribute :type
3
+ xml_attribute :unit
4
+ xml_attribute :ref_id, with_name: "refID"
5
+ xml_attribute :condition
6
+ xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
11
+
12
+ def metrics_item
13
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
14
+ name: type,
15
+ value: self,
16
+ description: description,
17
+ time_define: time_define,
18
+ )
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ class JMAFeed::JMX::WindSpeed < Giri::TextNodeInteger
2
+ xml_attribute :type
3
+ xml_attribute :unit
4
+ xml_attribute :ref_id, with_name: "refID"
5
+ xml_attribute :condition
6
+ xml_attribute :description
7
+
8
+ def time_define
9
+ (context.time_define_list || []).find{ref_id && ref_id == _1.time_id}
10
+ end
11
+
12
+ def metrics_item
13
+ @metrics_item ||= JMAFeed::WeatherAlert::MetricsItem.new(
14
+ name: type,
15
+ value: self,
16
+ description: description,
17
+ time_define: time_define,
18
+ )
19
+ end
20
+ end
@@ -22,19 +22,19 @@ class JMAFeed::VPHW50 < JMAFeed::ReportEntry
22
22
  end
23
23
  end
24
24
 
25
- def warning_district_report
25
+ def warning_area_type1
26
26
  warning.find{|w| w.type == "竜巻注意情報(発表細分)"}
27
27
  end
28
28
 
29
- def warning_district_1st
29
+ def warning_area_type2
30
30
  warning.find{|w| w.type == "竜巻注意情報(一次細分区域等)"}
31
31
  end
32
32
 
33
- def warning_district_aggregated
33
+ def warning_area_type3
34
34
  warning.find{|w| w.type == "竜巻注意情報(市町村等をまとめた地域等)"}
35
35
  end
36
36
 
37
- def warning_district_2nd
37
+ def warning_area_type4
38
38
  warning.find{|w| w.type == "竜巻注意情報(市町村等)"}
39
39
  end
40
40
  end
@@ -40,6 +40,7 @@ class JMAFeed::VPRN50 < JMAFeed::ReportEntry
40
40
 
41
41
  xml_node :body do
42
42
  xml_node_collection :meteorological_infos do
43
+ xml_attribute :type
43
44
  xml_node_collection :meteorological_info do
44
45
  date_time_node :date_time
45
46
  xml_node_collection :item do
@@ -82,19 +83,19 @@ class JMAFeed::VPRN50 < JMAFeed::ReportEntry
82
83
  end
83
84
  end
84
85
 
85
- def info_district_forecast
86
+ def info_area_type1
86
87
  meteorological_infos[0].meteorological_info[0]
87
88
  end
88
89
 
89
- def info_district_1st
90
+ def info_area_type2
90
91
  meteorological_infos[1].meteorological_info[0]
91
92
  end
92
93
 
93
- def info_district_aggregated
94
+ def info_area_type3
94
95
  meteorological_infos[2].meteorological_info[0]
95
96
  end
96
97
 
97
- def info_district_2nd
98
+ def info_area_type4
98
99
  meteorological_infos[3].meteorological_info[0]
99
100
  end
100
101
  end
@@ -11,26 +11,43 @@
11
11
  # </MeteorologicalInfos>
12
12
  #
13
13
  class JMAFeed::VPWW54 < JMAFeed::ReportEntry
14
+ class WarningItemKind < Giri::BaseNode
15
+ text_node :name
16
+ text_node :code
17
+ text_node :status
18
+ text_node :condition
19
+ xml_node :last_kind do
20
+ text_node :name
21
+ text_node :code
22
+ end
23
+ xml_node_collection :next_kinds do
24
+ xml_node :next_kind do
25
+ text_node :name
26
+ text_node :code
27
+ date_time_node :date_time do
28
+ xml_attribute :precision, type: :duration
29
+ end
30
+ text_node :sentence
31
+ end
32
+ end
33
+ xml_node :attention do
34
+ text_node :note, collection: true
35
+ end
36
+ xml_node :addition do
37
+ text_node :note, collection: true
38
+ end
39
+
40
+ def weather_alert
41
+ @weather_alert ||= JMAFeed::WeatherAlert.all.find{|a| a.code == code}
42
+ end
43
+ end
44
+
14
45
  xml_node :body do
46
+ text_node :notice, collection: true
15
47
  xml_node_collection :warning do
16
48
  xml_attribute :type
17
49
  xml_node_collection :item do
18
- xml_node_collection :kind do
19
- text_node :name
20
- text_node :code
21
- text_node :status
22
- text_node :condition
23
- xml_node :attention do
24
- text_node :note, collection: true
25
- end
26
- xml_node :addition do
27
- text_node :note, collection: true
28
- end
29
-
30
- def weather_alert
31
- @weather_alert ||= JMAFeed::WeatherAlert.all.find{|a| a.code == code}
32
- end
33
- end
50
+ xml_node_collection :kind, type: "JMAFeed::VPWW54::WarningItemKind"
34
51
  text_node :change_status
35
52
  xml_node :area, type: "JMAFeed::JMX::Area"
36
53
 
@@ -41,37 +58,209 @@ class JMAFeed::VPWW54 < JMAFeed::ReportEntry
41
58
  end
42
59
  end
43
60
  end
61
+
44
62
  xml_node :meteorological_infos do
45
63
  xml_attribute :type
46
64
  xml_node :time_series_info do
65
+ context :time_define_list do
66
+ time_defines.time_define
67
+ end
68
+
47
69
  xml_node :time_defines do
48
- xml_node_collection :time_define do
49
- xml_attribute :time_id, with_name: :lower_camelcase
50
- date_time_node :date_time
51
- duration_node :duration
52
- text_node :name
53
- end
70
+ xml_node_collection :time_define, type: "JMAFeed::JMX::TimeDefine"
54
71
  end
55
72
  xml_node_collection :item do
56
- # TODO
73
+ xml_node_collection :kind do
74
+ text_node :name
75
+ text_node :code
76
+ text_node :condition
77
+ xml_node_collection :property do
78
+ text_node :type
79
+
80
+ JMAFeed::WeatherAlert.metrics_components.each do |metr_component|
81
+ xml_node_collection "#{metr_component[:name]}_part".to_sym do
82
+ xml_node :base do
83
+ xml_node_collection metr_component[:name], type: "JMAFeed::JMX::#{metr_component[:name].to_s.camelize}"
84
+
85
+ xml_node_collection :local do
86
+ text_node :area_name
87
+ xml_node_collection metr_component[:name], type: "JMAFeed::JMX::#{metr_component[:name].to_s.camelize}"
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def weather_alert
95
+ @weather_alert ||= JMAFeed::WeatherAlert.all.find{|a| a.code == code}
96
+ end
97
+
98
+ # EXAMPLE of data structure
99
+ # {
100
+ # "土砂災害危険度" => {"全体" => [...]},
101
+ # "浸水害危険度" => {"全体" => [...]},
102
+ # "1時間最大雨量" => {"全体" => [...]},
103
+ # "3時間最大雨量" => {"全体" => [...]},
104
+ # }
105
+ # or
106
+ # {
107
+ # "土砂災害危険度" => {"山地" => [...], "平地" => [...]},
108
+ # "浸水害危険度" => {"山地" => [...], "平地" => [...]},
109
+ # "1時間最大雨量" => {"山地" => [...], "平地" => [...]},
110
+ # "3時間最大雨量" => {"山地" => [...], "平地" => [...]},
111
+ # }
112
+ def weather_alert_metrics
113
+ return nil unless weather_alert
114
+ weather_alert.metrics.map do |k,v|
115
+ metrics_part = property.find{_1.type == v[:property_type]}&.public_send("#{v[:name]}_part")
116
+ metrics_bases = metrics_part&.map(&:base)
117
+ metrics_items = if metrics_bases && metrics_bases.length > 0
118
+ primary_base = metrics_bases.first
119
+ metrics_bases_area_items = if primary_base.local && primary_base.local.length > 0
120
+ metrics_bases.map{|b|
121
+ b.local.map{|l|
122
+ [
123
+ l.area_name,
124
+ l.public_send(v[:name]).map(&:metrics_item)
125
+ ]
126
+ }.to_h
127
+ }
128
+ else
129
+ metrics_bases.map{|b|
130
+ [
131
+ [
132
+ "全体",
133
+ b.public_send(v[:name]).map(&:metrics_item)
134
+ ]
135
+ ].to_h
136
+ }
137
+ end
138
+
139
+ metrics_bases_area_items.find{|area_items|
140
+ local_area_name, area_metrics_items = area_items.first
141
+ area_metrics_items.first.name == k
142
+ }
143
+ else
144
+ nil
145
+ end
146
+
147
+ if metrics_items
148
+ [k, metrics_items]
149
+ else
150
+ nil
151
+ end
152
+ end.compact.to_h
153
+ end
154
+ end
155
+
156
+ JMAFeed::WeatherAlert.clusters.each do |cluster,alerts|
157
+ define_method cluster do
158
+ kind.find{|k| alerts.map(&:code).include?(k.code)}
159
+ end
160
+ end
161
+
162
+ xml_node :area, type: "JMAFeed::JMX::Area"
57
163
  end
58
164
  end
59
165
  end
60
166
 
61
- def warning_district_forecast
62
- warning[0]
167
+ def warning_area_type1
168
+ warning.find{|w| w.type == "気象警報・注意報(府県予報区等)"}
169
+ end
170
+
171
+ def warning_area_type2
172
+ warning.find{|w| w.type == "気象警報・注意報(一次細分区域等)"}
173
+ end
174
+
175
+ def warning_area_type3
176
+ warning.find{|w| w.type == "気象警報・注意報(市町村等をまとめた地域等)"}
177
+ end
178
+
179
+ def warning_area_type4
180
+ warning.find{|w| w.type == "気象警報・注意報(市町村等)"}
181
+ end
182
+ end
183
+
184
+ def detect_with_area(area, weather_alert_clusters: nil)
185
+ weather_alert_clusters ||= JMAFeed::WeatherAlert.clusters.keys
186
+ warning_item = detect_warning_item_with_area(area)
187
+ return nil unless warning_item
188
+
189
+ warning_alerts = weather_alert_clusters.map{|cluster|
190
+ warning_item.public_send(cluster)
191
+ }.compact
192
+
193
+ info_item = detect_info_item_with_area(area)
194
+ info_alerts = info_item && weather_alert_clusters.map{|cluster|
195
+ info_item.public_send(cluster)
196
+ }.compact
197
+
198
+ AreaAlert.new(
199
+ entry: self,
200
+ area: area,
201
+ weather_warnings: warning_alerts.map{|w|
202
+ WeatherWarning.new(w, info: info_alerts&.find{|i| i.code == w.code})
203
+ }
204
+ )
205
+ end
206
+
207
+ def detect_warning_item_with_area(area)
208
+ items = if area.is_a?(JMACode::AreaInformationCity)
209
+ body.warning_area_type4.item
210
+ else
211
+ if area.used_by.include?("area_forecast_type3_in_weather_alert")
212
+ body.warning_area_type3.item
213
+ elsif area.used_by.include?("area_forecast_type2_in_weather_alert")
214
+ body.warning_area_type2.item
215
+ elsif area.used_by.include?("area_forecast_type1_in_weather_alert")
216
+ body.warning_area_type1.item
217
+ else
218
+ nil
219
+ end
220
+ end
221
+ items&.find{_1.area.code == area.code}
222
+ end
223
+
224
+ def detect_info_item_with_area(area)
225
+ # NOTE: 当該電文で特別警報・警報・注意報の全てが解除される場合、MeteorologicalInfos 部は省略される。 (気象警報・注意報(H27)_解説資料.pdf > 3-3)
226
+ return nil unless body.meteorological_infos
227
+
228
+ if area.is_a?(JMACode::AreaInformationCity)
229
+ body.meteorological_infos.time_series_info.item.find{_1.area.code == area.code}
230
+ else
231
+ nil
232
+ end
233
+ end
234
+
235
+ class AreaAlert < Struct.new(:entry, :area, :weather_warnings, keyword_init: true)
236
+ end
237
+
238
+ class WeatherWarning < DelegateClass(WarningItemKind)
239
+ attr_reader :info
240
+ def initialize(warning, info:)
241
+ @warning = warning
242
+ @info = info
243
+ super(warning)
244
+ end
245
+
246
+ def cluster
247
+ weather_alert.cluster
248
+ end
249
+
250
+ def risk_level
251
+ weather_alert.risk_level
63
252
  end
64
253
 
65
- def warning_district_1st
66
- warning[1]
254
+ def attentions
255
+ attention&.note
67
256
  end
68
257
 
69
- def warning_district_aggregated
70
- warning[2]
258
+ def additions
259
+ addition&.note
71
260
  end
72
261
 
73
- def warning_district_2nd
74
- warning[3]
262
+ def metrics
263
+ info&.weather_alert_metrics
75
264
  end
76
265
  end
77
266
  end
@@ -0,0 +1,135 @@
1
+ # 地震情報(震源・震度に関する情報)
2
+ # https://xml.kishou.go.jp/tec_material.html
3
+ # 電文毎の解説資料 > 解説資料セットzip > 地震火山関連_解説資料.pdf > (ウ)地震情報(震源・震度に関する情報)
4
+ #
5
+ class JMAFeed::VXSE53 < JMAFeed::ReportEntry
6
+ xml_node :head do
7
+ text_node :event_id, with_name: "EventID"
8
+ end
9
+
10
+ xml_node :body do
11
+ xml_node :earthquake, type: "JMAFeed::JMX::Earthquake"
12
+
13
+ xml_node :intensity do
14
+ xml_node :observation do
15
+ xml_node :code_define do
16
+ text_node :type, collection: true do
17
+ xml_attribute :xpath
18
+ end
19
+ end
20
+
21
+ text_node :max_int
22
+
23
+ xml_node_collection :pref do
24
+ text_node :name
25
+ text_node :code
26
+ xml_node :max_int, type: "JMAFeed::JMX::EarthquakeIntensity"
27
+ text_node :revise
28
+ xml_node_collection :area do
29
+ text_node :name
30
+ text_node :code
31
+ xml_node :max_int, type: "JMAFeed::JMX::EarthquakeIntensity"
32
+ text_node :revise
33
+ xml_node_collection :city do
34
+ text_node :name
35
+ text_node :code
36
+ xml_node :max_int, type: "JMAFeed::JMX::EarthquakeIntensity"
37
+ text_node :revise
38
+ text_node :condition
39
+ xml_node_collection :intensity_station do
40
+ text_node :name
41
+ text_node :code
42
+ xml_node :int, type: "JMAFeed::JMX::EarthquakeIntensity"
43
+ text_node :revise
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ xml_node :comments do
52
+ xml_node :forecast_comment do
53
+ xml_attribute :code_type
54
+ text_node :text
55
+ text_node :code
56
+ end
57
+ xml_node :var_comment do
58
+ xml_attribute :code_type
59
+ text_node :text
60
+ text_node :code
61
+ end
62
+ xml_node :free_form_comment do
63
+ text_node :text
64
+ end
65
+ end
66
+ end
67
+
68
+ def detect_with_area(area)
69
+ pref = detect_pref_with_area(area)
70
+ return nil unless pref
71
+
72
+ earthquake = body.earthquake
73
+ comments = [
74
+ body.comments&.forecast_comment&.text,
75
+ body.comments&.var_comment&.text,
76
+ body.comments&.free_form_comment&.text,
77
+ ].compact
78
+ if area.is_a?(JMACode::Prefecture)
79
+ AreaAlert.new(entry: self, area: area, intensity: pref, earthquake: earthquake, comments: comments)
80
+ else
81
+ local_area = detect_local_area_with_area(area, pref)
82
+ if local_area && area.is_a?(JMACode::AreaForecastLocalE)
83
+ AreaAlert.new(entry: self, area: area, intensity: local_area, earthquake: earthquake, comments: comments)
84
+ else
85
+ city = detect_city_with_area(area, local_area)
86
+ if city && area.is_a?(JMACode::AreaInformationCity)
87
+ AreaAlert.new(entry: self, area: area, intensity: city, earthquake: earthquake, comments: comments)
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ def detect_pref_with_area(area)
94
+ intensity = body.intensity
95
+ return nil unless intensity
96
+
97
+ prefs = intensity.observation.pref
98
+ pref_code = if area.is_a?(JMACode::Prefecture)
99
+ area.code
100
+ elsif area.is_a?(JMACode::AreaForecastLocalE)
101
+ area.prefecture_code
102
+ elsif area.is_a?(JMACode::AreaInformationCity)
103
+ area.prefecture_code
104
+ else
105
+ nil
106
+ end
107
+
108
+ prefs.find{|pr| pr.code == pref_code}
109
+ end
110
+
111
+ def detect_local_area_with_area(area, pref_node)
112
+ area_code = if area.is_a?(JMACode::AreaForecastLocalE)
113
+ area.code
114
+ elsif area.is_a?(JMACode::AreaInformationCity)
115
+ area.area_forecast_local_e_code
116
+ else
117
+ nil
118
+ end
119
+
120
+ pref_node.area.find{|ar| ar.code == area_code}
121
+ end
122
+
123
+ def detect_city_with_area(area, local_area_node)
124
+ city_code = if area.is_a?(JMACode::AreaInformationCity)
125
+ area.code
126
+ else
127
+ nil
128
+ end
129
+
130
+ local_area_node.city.find{|c| c.code == city_code}
131
+ end
132
+
133
+ class AreaAlert < Struct.new(:entry, :area, :intensity, :earthquake, :comments, keyword_init: true)
134
+ end
135
+ end
@@ -1,10 +1,13 @@
1
1
  require "nokogiri"
2
- require "giri"
3
2
 
4
- class JMAFeed::ReportEntry < Giri::BaseNode
3
+ class JMAFeed::ReportEntry < JMAFeed::BaseNode
5
4
  class << self
6
5
  def get(url)
7
6
  xml = Net::HTTP.get(URI.parse(url))
7
+ build(xml)
8
+ end
9
+
10
+ def build(xml)
8
11
  doc = Nokogiri::XML(xml)
9
12
  new(doc.root)
10
13
  end
@@ -25,16 +28,30 @@ class JMAFeed::ReportEntry < Giri::BaseNode
25
28
  text_node :info_type
26
29
  text_node :info_kind
27
30
  text_node :info_kind_version
31
+ xml_node :headline do
32
+ text_node :text
33
+ end
28
34
  end
29
35
  end
30
36
 
31
37
  require "jma_feed/report_entry/jmx/area"
38
+ require "jma_feed/report_entry/jmx/time_define"
32
39
  require "jma_feed/report_entry/jmx/significancy"
33
40
  require "jma_feed/report_entry/jmx/precipitation"
34
41
  require "jma_feed/report_entry/jmx/water_level"
35
42
  require "jma_feed/report_entry/jmx/discharge"
43
+ require "jma_feed/report_entry/jmx/wind_direction"
44
+ require "jma_feed/report_entry/jmx/wind_speed"
45
+ require "jma_feed/report_entry/jmx/wave_height"
46
+ require "jma_feed/report_entry/jmx/visibility"
47
+ require "jma_feed/report_entry/jmx/snow_fall_depth"
48
+ require "jma_feed/report_entry/jmx/humidity"
49
+ require "jma_feed/report_entry/jmx/tidal_level"
50
+ require "jma_feed/report_entry/jmx/earthquake"
51
+ require "jma_feed/report_entry/jmx/earthquake_intensity"
36
52
  require "jma_feed/report_entry/vprn50"
37
53
  require "jma_feed/report_entry/vpww54"
38
54
  require "jma_feed/report_entry/vxko"
39
55
  require "jma_feed/report_entry/vphw50"
40
56
  require "jma_feed/report_entry/vptaii"
57
+ require "jma_feed/report_entry/vxse53"
@@ -56,4 +56,8 @@ class JMAFeed::Result
56
56
  def entries
57
57
  doc.entries
58
58
  end
59
+
60
+ def all_entries
61
+ doc.all_entries
62
+ end
59
63
  end
@@ -34,8 +34,8 @@ class JMAFeed::ResultDoc
34
34
  text('link[@rel="related"]/@href')
35
35
  end
36
36
 
37
- def entries
38
- @entries ||= doc.xpath('/atom:feed/atom:entry', namespace).map do |entry|
37
+ def all_entries
38
+ @all_entries ||= doc.xpath('/atom:feed/atom:entry', namespace).map do |entry|
39
39
  JMAFeed::ResultEntry.new(
40
40
  title: entry.xpath('atom:title', namespace).text,
41
41
  link: entry.xpath('atom:link/@href', namespace).text,
@@ -46,4 +46,8 @@ class JMAFeed::ResultDoc
46
46
  )
47
47
  end
48
48
  end
49
+
50
+ def entries
51
+ all_entries.uniq(&:identity)
52
+ end
49
53
  end
@@ -9,16 +9,39 @@ class JMAFeed::ResultEntry < Struct.new(
9
9
  time, number, report_code, report_area_code = identifier.split('_')
10
10
  end
11
11
 
12
+ # 気象警報・注意報(H27)_解説資料.pdf
13
+ # ---------------
14
+ # 「前回電文」とは、参照中の電文(当該電文)と、
15
+ # - 情報名称(Control/Title)
16
+ # - 運用種別(Control/Status)
17
+ # - 発信官署(Control/EditorialOffice)
18
+ # が同一である電文の中で、発表時刻(Head/ReportDateTime)が当該電文の直近過去である電文を指す。
19
+ #
20
+ # idに記載されるファイル名アンダースコア区切りの2番目がStatusを意味しているのかどうかは2024Aug時点で不明
21
+ # Status="通常" の電文しか取得できておらず確証はないが、この値をidに含んでいる可能性が高いと見切っての実装
22
+ def identity
23
+ [report_code, report_status, report_area_code].join('_')
24
+ end
25
+
12
26
  def report_code
13
27
  @report_code ||= identifier_components[2]
14
28
  end
15
29
 
16
30
  def report
17
31
  return nil if report_code.nil?
18
- @report ||= JMAFeed::Report.latest.detect{_1.has_code?(report_code)}
32
+ @report ||= JMAFeed::Report.get.detect{_1.has_code?(report_code)}
19
33
  end
20
34
 
21
35
  def report_area_code
22
36
  @report_area_code ||= identifier_components[3]
23
37
  end
38
+
39
+ def report_status
40
+ @report_status ||= identifier_components[1]
41
+ end
42
+
43
+ def get_report_entry!
44
+ return unless report
45
+ report.report_entry_class.get(id)
46
+ end
24
47
  end
@@ -1,3 +1,3 @@
1
1
  module JMAFeed
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.6"
3
3
  end
data/lib/jma_feed.rb CHANGED
@@ -11,10 +11,14 @@ require "jma_feed/report"
11
11
  require "jma_feed/result"
12
12
  require "jma_feed/result_doc"
13
13
  require "jma_feed/result_entry"
14
- require "jma_feed/api"
15
- require "jma_feed/api/extra"
16
- require "jma_feed/api/regular"
14
+ require "jma_feed/atom"
15
+ require "jma_feed/atom/extra"
16
+ require "jma_feed/atom/regular"
17
+ require "jma_feed/atom/eqvol"
18
+ require "jma_feed/atom/other"
19
+ require "jma_feed/node/base_node"
17
20
  require "jma_feed/entity/weather_alert"
21
+ require "jma_feed/entity/weather_alert/metrics_item"
18
22
  require "jma_feed/entity/risk_level"
19
23
 
20
24
  require "jma_feed/report_entry"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jma_feed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - metheglin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-09 00:00:00.000000000 Z
11
+ date: 2024-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -44,28 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.0.4
47
+ version: 0.0.6
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.0.4
54
+ version: 0.0.6
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: giri
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.0.3
61
+ version: 0.0.4
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.0.3
68
+ version: 0.0.4
69
69
  description: JMA Feed
70
70
  email: pigmybank@gmail.com
71
71
  executables: []
@@ -75,23 +75,38 @@ files:
75
75
  - README.md
76
76
  - data/jmaxml_20240216_format_v1_3_hyo1.csv
77
77
  - lib/jma_feed.rb
78
- - lib/jma_feed/api.rb
79
- - lib/jma_feed/api/extra.rb
80
- - lib/jma_feed/api/regular.rb
78
+ - lib/jma_feed/atom.rb
79
+ - lib/jma_feed/atom/eqvol.rb
80
+ - lib/jma_feed/atom/extra.rb
81
+ - lib/jma_feed/atom/other.rb
82
+ - lib/jma_feed/atom/regular.rb
81
83
  - lib/jma_feed/entity/risk_level.rb
82
84
  - lib/jma_feed/entity/weather_alert.rb
85
+ - lib/jma_feed/entity/weather_alert/metrics_item.rb
86
+ - lib/jma_feed/node/base_node.rb
83
87
  - lib/jma_feed/report.rb
84
88
  - lib/jma_feed/report_entry.rb
85
89
  - lib/jma_feed/report_entry/jmx/area.rb
86
90
  - lib/jma_feed/report_entry/jmx/discharge.rb
91
+ - lib/jma_feed/report_entry/jmx/earthquake.rb
92
+ - lib/jma_feed/report_entry/jmx/earthquake_intensity.rb
93
+ - lib/jma_feed/report_entry/jmx/humidity.rb
87
94
  - lib/jma_feed/report_entry/jmx/precipitation.rb
88
95
  - lib/jma_feed/report_entry/jmx/significancy.rb
96
+ - lib/jma_feed/report_entry/jmx/snow_fall_depth.rb
97
+ - lib/jma_feed/report_entry/jmx/tidal_level.rb
98
+ - lib/jma_feed/report_entry/jmx/time_define.rb
99
+ - lib/jma_feed/report_entry/jmx/visibility.rb
89
100
  - lib/jma_feed/report_entry/jmx/water_level.rb
101
+ - lib/jma_feed/report_entry/jmx/wave_height.rb
102
+ - lib/jma_feed/report_entry/jmx/wind_direction.rb
103
+ - lib/jma_feed/report_entry/jmx/wind_speed.rb
90
104
  - lib/jma_feed/report_entry/vphw50.rb
91
105
  - lib/jma_feed/report_entry/vprn50.rb
92
106
  - lib/jma_feed/report_entry/vptaii.rb
93
107
  - lib/jma_feed/report_entry/vpww54.rb
94
108
  - lib/jma_feed/report_entry/vxko.rb
109
+ - lib/jma_feed/report_entry/vxse53.rb
95
110
  - lib/jma_feed/result.rb
96
111
  - lib/jma_feed/result_doc.rb
97
112
  - lib/jma_feed/result_entry.rb