weather-forecasts 1.1.1 → 1.2.0

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.
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe WeatherForecasts::Client::SelectHourlyQuery do
4
+ let(:conditions) {
5
+ {
6
+ :latitude => 38.99,
7
+ :longitude => -77.01
8
+ }
9
+ }
10
+
11
+ subject { WeatherForecasts.client.select_hourly }
12
+
13
+ describe "#execute" do
14
+ before(:each) do
15
+ VCR.use_cassette('select_hourly_query') do
16
+ @response = subject.where(conditions).execute
17
+ end
18
+ end
19
+
20
+ it "returns a valid response" do
21
+ @response.should be_a(Hash)
22
+ @response[:parameters]["point1"][:temperature][:hourly][:values].first[:value].should be_a(Numeric)
23
+ end
24
+ end
25
+ end
@@ -23,10 +23,12 @@ Gem::Specification.new do |s|
23
23
 
24
24
  s.executables << 'wf-console'
25
25
 
26
+ s.add_runtime_dependency 'dwml', '~> 1.1.0', '>= 1.1.0'
26
27
  s.add_runtime_dependency 'savon', '~> 2.4.0', '>= 2.4.0'
28
+ s.add_runtime_dependency 'httpi', '~>2.1.0', '>= 2.1.0'
27
29
  s.add_runtime_dependency 'nokogiri', '~> 1.6.1', '>= 1.6.1'
28
30
  s.add_runtime_dependency 'multi_json', '~> 1.9.0', '>= 1.9.0'
29
- s.add_runtime_dependency 'activesupport', '~> 4.0.3', '>= 4.0.3'
31
+ s.add_runtime_dependency 'activesupport', '~> 4.1.0', '>= 4.1.0'
30
32
  s.add_runtime_dependency 'http_logger', '~> 0.4.2', '>= 0.4.2'
31
33
 
32
34
  s.post_install_message = "To start querying weather forecasts immediately, type `wf-console`."
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weather-forecasts
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Angelo Lakra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-02 00:00:00.000000000 Z
11
+ date: 2014-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dwml
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.1.0
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.1.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 1.1.0
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.0
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: savon
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +50,26 @@ dependencies:
30
50
  - - ">="
31
51
  - !ruby/object:Gem::Version
32
52
  version: 2.4.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: httpi
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 2.1.0
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 2.1.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 2.1.0
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 2.1.0
33
73
  - !ruby/object:Gem::Dependency
34
74
  name: nokogiri
35
75
  requirement: !ruby/object:Gem::Requirement
@@ -76,20 +116,20 @@ dependencies:
76
116
  requirements:
77
117
  - - "~>"
78
118
  - !ruby/object:Gem::Version
79
- version: 4.0.3
119
+ version: 4.1.0
80
120
  - - ">="
81
121
  - !ruby/object:Gem::Version
82
- version: 4.0.3
122
+ version: 4.1.0
83
123
  type: :runtime
84
124
  prerelease: false
85
125
  version_requirements: !ruby/object:Gem::Requirement
86
126
  requirements:
87
127
  - - "~>"
88
128
  - !ruby/object:Gem::Version
89
- version: 4.0.3
129
+ version: 4.1.0
90
130
  - - ">="
91
131
  - !ruby/object:Gem::Version
92
- version: 4.0.3
132
+ version: 4.1.0
93
133
  - !ruby/object:Gem::Dependency
94
134
  name: http_logger
95
135
  requirement: !ruby/object:Gem::Requirement
@@ -140,22 +180,18 @@ files:
140
180
  - lib/weather_forecasts/client/query/select_coordinates_by_zip_query.rb
141
181
  - lib/weather_forecasts/client/query/select_corner_coordinates_query.rb
142
182
  - lib/weather_forecasts/client/query/select_gridpoint_coordinates_query.rb
183
+ - lib/weather_forecasts/client/query/select_hourly_query.rb
143
184
  - lib/weather_forecasts/client/query/select_linepoint_coordinates_query.rb
144
185
  - lib/weather_forecasts/client/query/select_query.rb
145
186
  - lib/weather_forecasts/client/query/select_square_coordinates_query.rb
146
187
  - lib/weather_forecasts/client/query/selection_attributes.rb
147
188
  - lib/weather_forecasts/client/version.rb
148
- - lib/weather_forecasts/dwml.rb
149
- - lib/weather_forecasts/dwml/data_extractor.rb
150
- - lib/weather_forecasts/dwml/head_extractor.rb
151
- - lib/weather_forecasts/dwml/location.rb
152
- - lib/weather_forecasts/dwml/parameter_extractor.rb
153
- - lib/weather_forecasts/dwml/time_layout.rb
154
189
  - spec/fixtures/vcr_cassettes/select_by_days_query.yml
155
190
  - spec/fixtures/vcr_cassettes/select_coordinates_by_cities_query.yml
156
191
  - spec/fixtures/vcr_cassettes/select_coordinates_by_zip_query.yml
157
192
  - spec/fixtures/vcr_cassettes/select_corner_coordinates_query.yml
158
193
  - spec/fixtures/vcr_cassettes/select_gridpoint_coordinates_query.yml
194
+ - spec/fixtures/vcr_cassettes/select_hourly_query.yml
159
195
  - spec/fixtures/vcr_cassettes/select_linepoint_coordinates_query.yml
160
196
  - spec/fixtures/vcr_cassettes/select_query.yml
161
197
  - spec/fixtures/vcr_cassettes/select_square_coordinates_query.yml
@@ -165,6 +201,7 @@ files:
165
201
  - spec/lib/ndfd/client/query/select_coordinates_by_zip_query_spec.rb
166
202
  - spec/lib/ndfd/client/query/select_corner_coordinates_query_spec.rb
167
203
  - spec/lib/ndfd/client/query/select_gridpoint_coordinates_query_spec.rb
204
+ - spec/lib/ndfd/client/query/select_hourly_query_spec.rb
168
205
  - spec/lib/ndfd/client/query/select_linepoint_coordinates_query_spec.rb
169
206
  - spec/lib/ndfd/client/query/select_query_spec.rb
170
207
  - spec/lib/ndfd/client/query/select_square_coordinates_query_spec.rb
@@ -204,6 +241,7 @@ test_files:
204
241
  - spec/fixtures/vcr_cassettes/select_coordinates_by_zip_query.yml
205
242
  - spec/fixtures/vcr_cassettes/select_corner_coordinates_query.yml
206
243
  - spec/fixtures/vcr_cassettes/select_gridpoint_coordinates_query.yml
244
+ - spec/fixtures/vcr_cassettes/select_hourly_query.yml
207
245
  - spec/fixtures/vcr_cassettes/select_linepoint_coordinates_query.yml
208
246
  - spec/fixtures/vcr_cassettes/select_query.yml
209
247
  - spec/fixtures/vcr_cassettes/select_square_coordinates_query.yml
@@ -213,6 +251,7 @@ test_files:
213
251
  - spec/lib/ndfd/client/query/select_coordinates_by_zip_query_spec.rb
214
252
  - spec/lib/ndfd/client/query/select_corner_coordinates_query_spec.rb
215
253
  - spec/lib/ndfd/client/query/select_gridpoint_coordinates_query_spec.rb
254
+ - spec/lib/ndfd/client/query/select_hourly_query_spec.rb
216
255
  - spec/lib/ndfd/client/query/select_linepoint_coordinates_query_spec.rb
217
256
  - spec/lib/ndfd/client/query/select_query_spec.rb
218
257
  - spec/lib/ndfd/client/query/select_square_coordinates_query_spec.rb
@@ -1,38 +0,0 @@
1
- require 'multi_json'
2
-
3
- require 'weather_forecasts/dwml/head_extractor'
4
- require 'weather_forecasts/dwml/data_extractor'
5
-
6
- #
7
- # Note: See http://graphical.weather.gov/xml/mdl/XML/Design/MDL_XML_Design.pdf
8
- # for authoritative type definitions
9
- ################################################################################
10
-
11
- module WeatherForecasts
12
- class DWML
13
- attr_reader :output, :xmldoc
14
-
15
- def initialize(xmldoc)
16
- @xmldoc = xmldoc
17
- @output = {}
18
- end
19
-
20
- def process
21
- build_head
22
- build_data
23
- output
24
- end
25
-
26
- protected
27
-
28
- def build_head
29
- extractor = HeadExtractor.new(xmldoc.xpath("//dwml/head").first)
30
- @output.merge!(extractor.process)
31
- end
32
-
33
- def build_data
34
- extractor = DataExtractor.new(xmldoc.xpath("//dwml/data").first)
35
- @output.merge!(extractor.process)
36
- end
37
- end
38
- end
@@ -1,55 +0,0 @@
1
- require 'weather_forecasts/dwml/location'
2
- require 'weather_forecasts/dwml/time_layout'
3
- require 'weather_forecasts/dwml/parameter_extractor'
4
-
5
- module WeatherForecasts
6
- class DWML
7
- class DataExtractor
8
- attr_reader :output, :element
9
-
10
- def initialize(element)
11
- @element = element
12
- @locations = []
13
- @time_layouts = []
14
- @output = {}
15
- end
16
-
17
- def process
18
- extract_locations
19
- extract_time_layouts
20
- extract_parameters
21
-
22
- output
23
- end
24
-
25
- protected
26
-
27
- def extract_locations
28
- @locations = Location.extract(element.xpath("location"))
29
- end
30
-
31
- def extract_time_layouts
32
- @time_layouts = TimeLayout.extract(element.xpath("time-layout"))
33
- end
34
-
35
- def extract_parameters
36
- parameters = element.xpath("parameters")
37
-
38
- @output.merge!(
39
- :parameters => parameters.inject({}) do |memo, parameter|
40
- location = location_for_parameter(parameter)
41
- extractor = ParameterExtractor.new(parameter, location, @time_layouts)
42
- memo.merge!(location.location_key => extractor.process)
43
- memo
44
- end
45
- )
46
- end
47
-
48
- def location_for_parameter(parameter)
49
- @locations.detect do |location|
50
- parameter.attributes["applicable-location"].text == location.location_key
51
- end
52
- end
53
- end
54
- end
55
- end
@@ -1,49 +0,0 @@
1
- module WeatherForecasts
2
- class DWML
3
- class HeadExtractor
4
- attr_reader :output, :element
5
-
6
- def initialize(element)
7
- @element = element
8
- @output = {}
9
- end
10
-
11
- def process
12
- build_product
13
- build_source
14
- output
15
- end
16
-
17
- protected
18
-
19
- def build_product
20
- creation_date = Time.zone.parse(element.xpath('product/creation-date').text)
21
-
22
- @output.merge!(
23
- :product => {
24
- :title => element.xpath('product/title').text,
25
- :field => element.xpath('product/field').text,
26
- :category => element.xpath('product/category').text,
27
- :creation_date => creation_date
28
- }
29
- )
30
- end
31
-
32
- def build_source
33
- sub_center = element.xpath('source/production-center/sub-center').text
34
- production_center = element.xpath('source/production-center').text
35
-
36
- @output.merge!(
37
- :source => {
38
- :more_information => element.xpath('source/more-information').text,
39
- :product_center => production_center.gsub(sub_center, " - #{sub_center}"),
40
- :disclaimer => element.xpath('source/disclaimer').text,
41
- :credit => element.xpath('source/credit').text,
42
- :credit_logo => element.xpath('source/credit-logo').text,
43
- :feedback => element.xpath('source/feedback').text
44
- }
45
- )
46
- end
47
- end
48
- end
49
- end
@@ -1,33 +0,0 @@
1
- module WeatherForecasts
2
- class DWML
3
- class Location
4
- class << self
5
- def extract(elements)
6
- elements.map { |element| new(element) }
7
- end
8
- end
9
-
10
- attr_reader :element, :location_key, :latitude, :longitude
11
-
12
- def initialize(element)
13
- @element = element
14
-
15
- extract_key
16
- extract_coords
17
- end
18
-
19
- protected
20
-
21
- def extract_key
22
- @location_key = element.xpath("location-key").first.text
23
- end
24
-
25
- def extract_coords
26
- point = element.xpath('point').first
27
-
28
- @latitude = point.attributes["latitude"].text.to_f
29
- @longitude = point.attributes["longitude"].text.to_f
30
- end
31
- end
32
- end
33
- end
@@ -1,281 +0,0 @@
1
- module WeatherForecasts
2
- class DWML
3
- class ParameterExtractor
4
- attr_reader :output, :element, :location, :time_layouts
5
-
6
- def initialize(element, location, time_layouts)
7
- @element = element
8
- @location = location
9
- @time_layouts = time_layouts
10
-
11
- @output = {
12
- :latitude => location.latitude,
13
- :longitude => location.longitude
14
- }
15
- end
16
-
17
- def process
18
- extract_temperatures
19
- extract_precipitation
20
- extract_wind_speed
21
- extract_wind_direction
22
- extract_cloud_cover
23
- extract_probability_of_precipitation
24
- extract_fire_weather
25
- extract_convective_hazard
26
- extract_climate_anomaly
27
- extract_humidity
28
- extract_weather
29
- extract_conditions_icons
30
- extract_hazards
31
- extract_water_state
32
-
33
- output
34
- end
35
-
36
- protected
37
-
38
- def extract_temperatures
39
- extract_basic_time_series(:temperature)
40
- end
41
-
42
- def extract_precipitation
43
- extract_basic_time_series(:precipitation)
44
- end
45
-
46
- def extract_wind_speed
47
- extract_basic_time_series(:"wind-speed")
48
- end
49
-
50
- def extract_wind_direction
51
- extract_basic_time_series(:direction)
52
- end
53
-
54
- def extract_cloud_cover
55
- extract_basic_time_series(:"cloud-amount")
56
- end
57
-
58
- def extract_probability_of_precipitation
59
- extract_basic_time_series(:"probability-of-precipitation")
60
- end
61
-
62
- def extract_humidity
63
- extract_basic_time_series(:humidity)
64
- end
65
-
66
- def extract_fire_weather
67
- extract_basic_time_series(:"fire-weather")
68
- end
69
-
70
- def extract_water_state
71
- node = element.xpath("water-state").first
72
- return if node.blank?
73
-
74
- @output[:"water-state"] = {}
75
- layout = lookup_time_layout(node)
76
-
77
- waves_node = node.xpath("waves").first
78
- @output[:"water-state"][:type] = waves_node.attributes["type"].text
79
- @output[:"water-state"][:unit] = waves_node.attributes["units"].text
80
- @output[:"water-state"][:values] = []
81
-
82
- waves_node.xpath("value").each_with_index do |value, index|
83
- @output[:"water-state"][:values] << {
84
- :value => value.text,
85
- :start_time => layout.valid_times[index].start
86
- }
87
- end
88
- end
89
-
90
- def extract_hazards
91
- node = element.xpath("hazards").first
92
- return if node.blank?
93
-
94
- layout = lookup_time_layout(node)
95
-
96
- @output[:hazards] = {
97
- :name => node.xpath("name").first.text,
98
- :conditions => node.xpath("hazard-conditions").each_with_index.map do |condition_node, index|
99
- hazard_node = condition_node.xpath("hazard").first
100
- next if hazard_node.blank?
101
-
102
- {
103
- :code => hazard_node.attributes["hazardCode"].text,
104
- :phenomena => hazard_node.attributes["phenomena"].text,
105
- :significance => hazard_node.attributes["significance"].text,
106
- :type => hazard_node.attributes["hazardType"].text,
107
- :url => hazard_node.xpath("hazardTextURL").first.text,
108
- :start_time => layout.valid_times[index].start
109
- }
110
- end.compact
111
- }
112
- end
113
-
114
- def extract_conditions_icons
115
- node = element.xpath("conditions-icon").first
116
- return if node.blank?
117
-
118
- layout = lookup_time_layout(node)
119
-
120
- @output[:"conditions-icon"] = {
121
- :name => node.xpath("name").text,
122
- :type => node.attributes["type"].text,
123
- :links => node.xpath("icon-link").each_with_index.map do |icon_node, index|
124
- {
125
- :link => icon_node.text,
126
- :start_time => layout.valid_times[index].start
127
- }
128
- end
129
- }
130
- end
131
-
132
- def extract_convective_hazard
133
- return if element.xpath("convective-hazard").blank?
134
-
135
- @output[:"convective-hazard"] ||= {
136
- :outlook => { :name => nil, :values => []},
137
- :"severe-component" => []
138
- }
139
-
140
- extract_convective_hazard_outlook
141
- extract_convective_hazard_severity
142
- end
143
-
144
- def extract_convective_hazard_outlook
145
- outlook_node = element.xpath("convective-hazard/outlook").first
146
- layout = lookup_time_layout(outlook_node)
147
-
148
- @output[:"convective-hazard"][:outlook][:name] = outlook_node.xpath("node").text
149
-
150
- outlook_node.xpath("value").each_with_index do |value, index|
151
- @output[:"convective-hazard"][:outlook][:values] << {
152
- :start_time => layout.valid_times[index].start,
153
- :end_time => layout.valid_times[index].stop,
154
- :value => value.text
155
- }
156
- end
157
- end
158
-
159
- def extract_convective_hazard_severity
160
- element.xpath("convective-hazard/severe-component").each do |node|
161
- layout = lookup_time_layout(node)
162
-
163
- hsh = {
164
- :name => node.xpath("name").first.text,
165
- :type => node.attributes["type"].text,
166
- :unit => node.attributes["units"].text,
167
- :values => node.xpath("value").each_with_index.map do |value, index|
168
- {
169
- :value => value.text,
170
- :start_time => layout.valid_times[index].start,
171
- :end_time => layout.valid_times[index].stop
172
- }
173
- end
174
- }
175
-
176
- @output[:"convective-hazard"][:"severe-component"] << hsh
177
- end
178
- end
179
-
180
- def extract_climate_anomaly
181
- return if element.xpath("climate-anomaly").blank?
182
-
183
- [:weekly, :monthly, :seasonal].each do |period|
184
- element.xpath("climate-anomaly/#{period.to_s}").each_with_index do |node|
185
- layout = lookup_time_layout(node)
186
- valid_time = layout.valid_times.first
187
-
188
- @output[:"climate-anomaly"] ||= {}
189
- @output[:"climate-anomaly"][period] ||= []
190
- @output[:"climate-anomaly"][period] << {
191
- :name => node.xpath("name").first.text,
192
- :value => node.xpath("value").first.text,
193
- :type => node.attributes["type"].text,
194
- :unit => node.attributes["units"].text,
195
- :start_time => valid_time.start,
196
- :end_time => valid_time.stop
197
- }
198
- end
199
- end
200
- end
201
-
202
- def extract_weather
203
- node = element.xpath("weather")
204
- return if node.blank?
205
-
206
- node.map do |weather_node|
207
- @output[:weather] ||= {}
208
- @output[:weather][:name] = weather_node.xpath("name").text
209
- @output[:weather][:conditions] ||= []
210
-
211
- layout = lookup_time_layout(weather_node)
212
-
213
- weather_node.xpath("weather-conditions").each_with_index do |condition, index|
214
- value = condition.xpath("value").first
215
- next if value.blank?
216
-
217
- visibility_node = value.xpath("visibility").first
218
- visibility = if visibility_node.present? && visibility_node.text.present?
219
- {
220
- :unit => visibility_node.attributes["units"].text,
221
- :value => visibility_node.text.to_f
222
- }
223
- else
224
- ""
225
- end
226
-
227
- hsh = {
228
- :start_time => layout.valid_times[index].start,
229
- :coverage => value.attributes["coverage"].text,
230
- :intensity => value.attributes["intensity"].text,
231
- :"weather-type" => value.attributes["weather-type"].text,
232
- :qualifier => value.attributes["qualifier"].text,
233
- :visibility => visibility
234
- }
235
-
236
- additive = value.attributes["additive"]
237
- hsh.merge!(:additive => additive) if additive.present?
238
-
239
- @output[:weather][:conditions] << hsh
240
- end
241
- end
242
- end
243
-
244
- def extract_basic_time_series(metric)
245
- metric_node = element.xpath(metric.to_s)
246
- return if metric_node.blank?
247
-
248
- metric_node.map do |node|
249
- layout = lookup_time_layout(node)
250
- type = node.attributes["type"].text.to_sym
251
- unit = node.attributes["units"].try(:text)
252
-
253
- @output[metric] ||= {}
254
- @output[metric][type] ||= {}
255
- @output[metric][type][:name] = node.xpath("name").text
256
- @output[metric][type][:values] = []
257
-
258
- node.xpath("value").each_with_index do |value, index|
259
- hsh = {
260
- :value => value.text.to_f,
261
- :start_time => layout.valid_times[index].start
262
- }
263
-
264
- end_time = layout.valid_times[index].stop
265
-
266
- hsh.merge!(:unit => unit) if unit.present?
267
- hsh.merge!(:end_time => end_time) if end_time.present?
268
-
269
- @output[metric][type][:values] << hsh
270
- end
271
- end
272
- end
273
-
274
- def lookup_time_layout(node)
275
- @time_layouts.detect do |layout|
276
- node.attributes["time-layout"].text == layout.layout_key
277
- end
278
- end
279
- end
280
- end
281
- end