barometer 0.8.0 → 0.9.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.
Files changed (321) hide show
  1. data/.gitignore +2 -0
  2. data/.pelusa.yml +7 -0
  3. data/.travis.yml +6 -3
  4. data/Gemfile +11 -1
  5. data/README.md +89 -244
  6. data/Rakefile +1 -1
  7. data/barometer.gemspec +22 -24
  8. data/lib/barometer.rb +14 -65
  9. data/lib/barometer/base.rb +35 -65
  10. data/lib/barometer/data.rb +15 -20
  11. data/lib/barometer/data/attribute.rb +19 -0
  12. data/lib/barometer/data/attributes/distance.rb +11 -0
  13. data/lib/barometer/data/attributes/float.rb +11 -0
  14. data/lib/barometer/data/attributes/integer.rb +11 -0
  15. data/lib/barometer/data/attributes/location.rb +11 -0
  16. data/lib/barometer/data/attributes/pressure.rb +11 -0
  17. data/lib/barometer/data/attributes/sun.rb +15 -0
  18. data/lib/barometer/data/attributes/temperature.rb +11 -0
  19. data/lib/barometer/data/attributes/time.rb +11 -0
  20. data/lib/barometer/data/attributes/vector.rb +11 -0
  21. data/lib/barometer/data/attributes/zone.rb +11 -0
  22. data/lib/barometer/data/convertable_units.rb +145 -0
  23. data/lib/barometer/data/coordinates.rb +16 -0
  24. data/lib/barometer/data/distance.rb +14 -133
  25. data/lib/barometer/data/geo.rb +22 -59
  26. data/lib/barometer/data/location.rb +14 -20
  27. data/lib/barometer/data/pressure.rb +14 -135
  28. data/lib/barometer/data/sun.rb +24 -24
  29. data/lib/barometer/data/temperature.rb +14 -169
  30. data/lib/barometer/data/vector.rb +44 -0
  31. data/lib/barometer/data/zone.rb +109 -112
  32. data/lib/barometer/query.rb +23 -161
  33. data/lib/barometer/query/base.rb +88 -0
  34. data/lib/barometer/query/converter.rb +64 -0
  35. data/lib/barometer/query/converters/from_coordinates_to_noaa_station_id.rb +30 -0
  36. data/lib/barometer/query/converters/from_geocode_to_coordinates.rb +28 -0
  37. data/lib/barometer/query/converters/from_short_zipcode_to_zipcode.rb +28 -0
  38. data/lib/barometer/query/converters/from_weather_id_to_geocode.rb +30 -0
  39. data/lib/barometer/query/converters/from_woe_id_or_ipv4_to_geocode.rb +32 -0
  40. data/lib/barometer/query/converters/to_geocode.rb +30 -0
  41. data/lib/barometer/query/converters/to_weather_id.rb +30 -0
  42. data/lib/barometer/query/converters/to_woe_id.rb +30 -0
  43. data/lib/barometer/query/format.rb +59 -0
  44. data/lib/barometer/query/formats/base.rb +22 -0
  45. data/lib/barometer/query/formats/coordinates.rb +14 -0
  46. data/lib/barometer/query/formats/geocode.rb +15 -0
  47. data/lib/barometer/query/formats/icao.rb +35 -0
  48. data/lib/barometer/query/formats/ipv4_address.rb +19 -0
  49. data/lib/barometer/query/formats/noaa_station_id.rb +15 -0
  50. data/lib/barometer/query/formats/postalcode.rb +20 -0
  51. data/lib/barometer/query/formats/short_zipcode.rb +15 -0
  52. data/lib/barometer/{translations → query/formats/translations}/icao_country_codes.yml +0 -0
  53. data/lib/barometer/{translations → query/formats/translations}/weather_country_codes.yml +0 -0
  54. data/lib/barometer/query/formats/unknown.rb +14 -0
  55. data/lib/barometer/query/formats/weather_id.rb +33 -0
  56. data/lib/barometer/query/formats/woe_id.rb +28 -0
  57. data/lib/barometer/query/formats/zipcode.rb +15 -0
  58. data/lib/barometer/query/service.rb +13 -0
  59. data/lib/barometer/query/services/apis/geonames_timezone.rb +26 -0
  60. data/lib/barometer/query/services/apis/google_geocode.rb +35 -0
  61. data/lib/barometer/query/services/apis/noaa_station.rb +31 -0
  62. data/lib/barometer/query/services/apis/weather_id.rb +35 -0
  63. data/lib/barometer/query/services/apis/wunderground_timezone.rb +26 -0
  64. data/lib/barometer/query/services/apis/yahoo_placefinder.rb +35 -0
  65. data/lib/barometer/query/services/apis/yahoo_weather.rb +31 -0
  66. data/lib/barometer/query/services/from_weather_id.rb +64 -0
  67. data/lib/barometer/query/services/geonames_timezone.rb +18 -0
  68. data/lib/barometer/query/services/google_geocode.rb +106 -0
  69. data/lib/barometer/query/services/noaa_station_id.rb +28 -0
  70. data/lib/barometer/query/services/to_weather_id.rb +25 -0
  71. data/lib/barometer/query/services/to_woe_id.rb +29 -0
  72. data/lib/barometer/query/services/wunderground_timezone.rb +18 -0
  73. data/lib/barometer/query/services/yahoo_geocode.rb +69 -0
  74. data/lib/barometer/response.rb +12 -0
  75. data/lib/barometer/response/base.rb +57 -0
  76. data/lib/barometer/response/current.rb +27 -0
  77. data/lib/barometer/response/prediction.rb +41 -0
  78. data/lib/barometer/response/prediction_collection.rb +48 -0
  79. data/lib/barometer/utils.rb +17 -0
  80. data/lib/barometer/utils/address.rb +33 -0
  81. data/lib/barometer/utils/api.rb +30 -0
  82. data/lib/barometer/utils/config_reader.rb +40 -0
  83. data/lib/barometer/utils/get.rb +17 -0
  84. data/lib/barometer/utils/json_reader.rb +22 -0
  85. data/lib/barometer/utils/payload.rb +100 -0
  86. data/lib/barometer/utils/payload_request.rb +37 -0
  87. data/lib/barometer/utils/post.rb +24 -0
  88. data/lib/barometer/utils/time.rb +78 -0
  89. data/lib/barometer/{translations → utils/translations}/zone_codes.yml +0 -0
  90. data/lib/barometer/utils/versioned_registration.rb +70 -0
  91. data/lib/barometer/utils/xml_reader.rb +27 -0
  92. data/lib/barometer/utils/zone_code_lookup.rb +30 -0
  93. data/lib/barometer/version.rb +1 -1
  94. data/lib/barometer/weather.rb +44 -173
  95. data/lib/barometer/weather_service.rb +41 -0
  96. data/lib/barometer/weather_services/base.rb +50 -0
  97. data/lib/barometer/weather_services/forecast_io.rb +36 -0
  98. data/lib/barometer/weather_services/forecast_io/api.rb +22 -0
  99. data/lib/barometer/weather_services/forecast_io/query.rb +38 -0
  100. data/lib/barometer/weather_services/forecast_io/response.rb +31 -0
  101. data/lib/barometer/weather_services/forecast_io/response/current_weather.rb +78 -0
  102. data/lib/barometer/weather_services/forecast_io/response/forecasted_weather.rb +74 -0
  103. data/lib/barometer/weather_services/forecast_io/response/location.rb +19 -0
  104. data/lib/barometer/weather_services/forecast_io/response/timezone.rb +25 -0
  105. data/lib/barometer/weather_services/noaa.rb +21 -305
  106. data/lib/barometer/weather_services/noaa/current_api.rb +25 -0
  107. data/lib/barometer/weather_services/noaa/current_query.rb +30 -0
  108. data/lib/barometer/weather_services/noaa/current_response.rb +29 -0
  109. data/lib/barometer/weather_services/noaa/forecast_api.rb +25 -0
  110. data/lib/barometer/weather_services/noaa/forecast_query.rb +39 -0
  111. data/lib/barometer/weather_services/noaa/forecast_response.rb +28 -0
  112. data/lib/barometer/weather_services/noaa/response/current_location.rb +42 -0
  113. data/lib/barometer/weather_services/noaa/response/current_station.rb +46 -0
  114. data/lib/barometer/weather_services/noaa/response/current_weather.rb +82 -0
  115. data/lib/barometer/weather_services/noaa/response/forecasted_weather.rb +90 -0
  116. data/lib/barometer/weather_services/noaa/response/location.rb +19 -0
  117. data/lib/barometer/weather_services/noaa/response/timezone.rb +15 -0
  118. data/lib/barometer/weather_services/response.rb +9 -0
  119. data/lib/barometer/weather_services/response/location.rb +42 -0
  120. data/lib/barometer/weather_services/response/time_zone.rb +19 -0
  121. data/lib/barometer/weather_services/weather_bug.rb +24 -280
  122. data/lib/barometer/weather_services/weather_bug/current_api.rb +26 -0
  123. data/lib/barometer/weather_services/weather_bug/current_response.rb +33 -0
  124. data/lib/barometer/weather_services/weather_bug/forecast_api.rb +26 -0
  125. data/lib/barometer/weather_services/weather_bug/forecast_response.rb +29 -0
  126. data/lib/barometer/weather_services/weather_bug/query.rb +42 -0
  127. data/lib/barometer/weather_services/weather_bug/response/current_weather.rb +82 -0
  128. data/lib/barometer/weather_services/weather_bug/response/forecasted_weather.rb +67 -0
  129. data/lib/barometer/weather_services/weather_bug/response/location.rb +23 -0
  130. data/lib/barometer/weather_services/weather_bug/response/station.rb +43 -0
  131. data/lib/barometer/weather_services/weather_bug/response/sun.rb +32 -0
  132. data/lib/barometer/weather_services/weather_bug/response/time_helper.rb +52 -0
  133. data/lib/barometer/weather_services/weather_bug/response/timezone.rb +15 -0
  134. data/lib/barometer/weather_services/wunderground_v1.rb +32 -0
  135. data/lib/barometer/weather_services/wunderground_v1/current_api.rb +21 -0
  136. data/lib/barometer/weather_services/wunderground_v1/current_response.rb +31 -0
  137. data/lib/barometer/weather_services/wunderground_v1/forecast_api.rb +21 -0
  138. data/lib/barometer/weather_services/wunderground_v1/forecast_response.rb +33 -0
  139. data/lib/barometer/weather_services/wunderground_v1/query.rb +30 -0
  140. data/lib/barometer/weather_services/wunderground_v1/response/current_weather.rb +92 -0
  141. data/lib/barometer/weather_services/wunderground_v1/response/forecasted_weather.rb +87 -0
  142. data/lib/barometer/weather_services/wunderground_v1/response/full_timezone.rb +22 -0
  143. data/lib/barometer/weather_services/wunderground_v1/response/location.rb +43 -0
  144. data/lib/barometer/weather_services/wunderground_v1/response/station.rb +39 -0
  145. data/lib/barometer/weather_services/wunderground_v1/response/sun.rb +53 -0
  146. data/lib/barometer/weather_services/wunderground_v1/response/timezone.rb +15 -0
  147. data/lib/barometer/weather_services/yahoo.rb +16 -198
  148. data/lib/barometer/weather_services/yahoo/api.rb +21 -0
  149. data/lib/barometer/weather_services/yahoo/query.rb +42 -0
  150. data/lib/barometer/weather_services/yahoo/response.rb +39 -0
  151. data/lib/barometer/weather_services/yahoo/response/current_weather.rb +86 -0
  152. data/lib/barometer/weather_services/yahoo/response/forecasted_weather.rb +71 -0
  153. data/lib/barometer/weather_services/yahoo/response/location.rb +47 -0
  154. data/lib/barometer/weather_services/yahoo/response/sun.rb +43 -0
  155. data/lib/barometer/weather_services/yahoo/response/timezone.rb +15 -0
  156. data/spec/barometer_spec.rb +18 -120
  157. data/spec/base_spec.rb +114 -0
  158. data/spec/cassettes/Converter_FromCoordinatesToNoaaStationId.json +1 -0
  159. data/spec/cassettes/Converter_FromWeatherIdToGeocode.json +1 -0
  160. data/spec/cassettes/Converter_FromWoeIdOrIpv4ToGeocode.json +1 -0
  161. data/spec/cassettes/Converter_ToGeocode.json +1 -0
  162. data/spec/cassettes/Converter_ToWeatherId.json +1 -0
  163. data/spec/cassettes/Converter_ToWoeId.json +1 -0
  164. data/spec/cassettes/Service_FromWeatherId.json +1 -0
  165. data/spec/cassettes/Service_GoogleGeocode.json +1 -0
  166. data/spec/cassettes/Service_NoaaStation.json +1 -0
  167. data/spec/cassettes/Service_ToWeatherId.json +1 -0
  168. data/spec/cassettes/Service_ToWoeId.json +1 -0
  169. data/spec/cassettes/Service_YahooGeocode.json +1 -0
  170. data/spec/cassettes/WeatherService_ForecastIo.json +1 -0
  171. data/spec/cassettes/WeatherService_Noaa.json +1 -1
  172. data/spec/cassettes/WeatherService_WeatherBug.json +1 -1
  173. data/spec/cassettes/WeatherService_WundergroundV1.json +1 -0
  174. data/spec/cassettes/WeatherService_Yahoo.json +1 -1
  175. data/spec/data/attributes/distance_spec.rb +60 -0
  176. data/spec/data/attributes/location_spec.rb +41 -0
  177. data/spec/data/attributes/pressure_spec.rb +60 -0
  178. data/spec/data/attributes/sun_spec.rb +33 -0
  179. data/spec/data/attributes/temperature_spec.rb +60 -0
  180. data/spec/data/attributes/time_spec.rb +58 -0
  181. data/spec/data/attributes/vector_spec.rb +43 -0
  182. data/spec/data/attributes/zone_spec.rb +34 -0
  183. data/spec/data/convertable_units_spec.rb +299 -0
  184. data/spec/data/coordinates_spec.rb +15 -0
  185. data/spec/data/distance_spec.rb +49 -333
  186. data/spec/data/geo_spec.rb +72 -71
  187. data/spec/data/location_spec.rb +70 -65
  188. data/spec/data/pressure_spec.rb +49 -333
  189. data/spec/data/sun_spec.rb +57 -81
  190. data/spec/data/temperature_spec.rb +49 -393
  191. data/spec/data/vector_spec.rb +100 -0
  192. data/spec/data/zone_spec.rb +199 -266
  193. data/spec/query/base_spec.rb +296 -0
  194. data/spec/query/converter_spec.rb +98 -0
  195. data/spec/query/converters/from_coordinates_to_noaa_station_id_spec.rb +35 -0
  196. data/spec/query/converters/from_geocode_to_coordinates_spec.rb +25 -0
  197. data/spec/query/converters/from_short_zipcode_to_zipcode_spec.rb +31 -0
  198. data/spec/query/converters/from_weather_id_to_geocode_spec.rb +40 -0
  199. data/spec/query/converters/from_woe_id_or_ipv4_to_geocode_spec.rb +51 -0
  200. data/spec/query/converters/to_geocode_spec.rb +99 -0
  201. data/spec/query/converters/to_weather_id_spec.rb +35 -0
  202. data/spec/query/converters/to_woe_id_spec.rb +74 -0
  203. data/spec/query/formats/base_spec.rb +15 -0
  204. data/spec/query/formats/coordinates_spec.rb +13 -0
  205. data/spec/query/formats/geocode_spec.rb +9 -0
  206. data/spec/query/formats/icao_spec.rb +20 -0
  207. data/spec/query/formats/ipv4_address_spec.rb +33 -0
  208. data/spec/query/formats/noaa_station_id_spec.rb +9 -0
  209. data/spec/query/formats/postalcode_spec.rb +18 -0
  210. data/spec/query/formats/short_zipcode_spec.rb +18 -0
  211. data/spec/query/formats/unknown_spec.rb +9 -0
  212. data/spec/query/formats/weather_id_spec.rb +31 -0
  213. data/spec/query/formats/woe_id_spec.rb +45 -0
  214. data/spec/query/formats/zipcode_spec.rb +18 -0
  215. data/spec/query/formats_spec.rb +55 -0
  216. data/spec/query/services/from_weather_id_spec.rb +54 -0
  217. data/spec/query/services/google_geocode_spec.rb +60 -0
  218. data/spec/query/services/noaa_station_id_spec.rb +23 -0
  219. data/spec/query/services/to_weather_id_spec.rb +23 -0
  220. data/spec/query/services/to_woe_id_spec.rb +51 -0
  221. data/spec/query/services/yahoo_geocode_spec.rb +72 -0
  222. data/spec/response/base_spec.rb +103 -0
  223. data/spec/response/current_spec.rb +33 -0
  224. data/spec/response/predicition_spec.rb +65 -0
  225. data/spec/response/prediction_collection_spec.rb +97 -0
  226. data/spec/spec_helper.rb +14 -12
  227. data/spec/support/key_file_parser.rb +22 -0
  228. data/spec/support/matchers/formats.rb +36 -0
  229. data/spec/support/matchers/have_data.rb +46 -0
  230. data/spec/support/matchers/have_field.rb +128 -0
  231. data/spec/support/matchers/have_forecast.rb +46 -0
  232. data/spec/support/matchers/path.rb +23 -0
  233. data/spec/support/query_factory.rb +20 -0
  234. data/spec/utils/address_spec.rb +67 -0
  235. data/spec/utils/config_reader_spec.rb +157 -0
  236. data/spec/utils/get_spec.rb +22 -0
  237. data/spec/utils/payload_request_spec.rb +69 -0
  238. data/spec/utils/payload_spec.rb +168 -0
  239. data/spec/utils/post_spec.rb +20 -0
  240. data/spec/utils/time_spec.rb +93 -0
  241. data/spec/utils/versioned_registration_spec.rb +105 -0
  242. data/spec/weather_services/base_spec.rb +116 -0
  243. data/spec/weather_services/forecast_io_spec.rb +71 -0
  244. data/spec/weather_services/noaa/current_response_spec.rb +22 -0
  245. data/spec/weather_services/noaa/forecast_response_spec.rb +33 -0
  246. data/spec/weather_services/noaa_spec.rb +68 -166
  247. data/spec/weather_services/weather_bug/current_response_spec.rb +64 -0
  248. data/spec/weather_services/weather_bug/forecast_response_spec.rb +23 -0
  249. data/spec/weather_services/weather_bug_spec.rb +62 -202
  250. data/spec/weather_services/wunderground_v1/current_response_spec.rb +19 -0
  251. data/spec/weather_services/wunderground_v1/forecast_response_spec.rb +62 -0
  252. data/spec/weather_services/wunderground_v1_spec.rb +78 -0
  253. data/spec/weather_services/yahoo/response_spec.rb +73 -0
  254. data/spec/weather_services/yahoo_spec.rb +52 -135
  255. data/spec/weather_services_spec.rb +103 -0
  256. data/spec/weather_spec.rb +167 -347
  257. metadata +342 -123
  258. data/.document +0 -5
  259. data/TODO +0 -60
  260. data/bin/barometer +0 -441
  261. data/lib/barometer/data/local_datetime.rb +0 -145
  262. data/lib/barometer/data/local_time.rb +0 -134
  263. data/lib/barometer/data/speed.rb +0 -158
  264. data/lib/barometer/data/units.rb +0 -49
  265. data/lib/barometer/formats.rb +0 -13
  266. data/lib/barometer/formats/coordinates.rb +0 -57
  267. data/lib/barometer/formats/format.rb +0 -64
  268. data/lib/barometer/formats/geocode.rb +0 -60
  269. data/lib/barometer/formats/icao.rb +0 -37
  270. data/lib/barometer/formats/postalcode.rb +0 -22
  271. data/lib/barometer/formats/short_zipcode.rb +0 -17
  272. data/lib/barometer/formats/weather_id.rb +0 -92
  273. data/lib/barometer/formats/woe_id.rb +0 -150
  274. data/lib/barometer/formats/zipcode.rb +0 -31
  275. data/lib/barometer/key_file_parser.rb +0 -20
  276. data/lib/barometer/measurements/measurement.rb +0 -202
  277. data/lib/barometer/measurements/result.rb +0 -207
  278. data/lib/barometer/measurements/result_array.rb +0 -75
  279. data/lib/barometer/services.rb +0 -19
  280. data/lib/barometer/weather_services/service.rb +0 -189
  281. data/lib/barometer/weather_services/wunderground.rb +0 -264
  282. data/lib/barometer/web_services/geocode.rb +0 -34
  283. data/lib/barometer/web_services/noaa_station_id.rb +0 -53
  284. data/lib/barometer/web_services/placemaker.rb +0 -95
  285. data/lib/barometer/web_services/timezone.rb +0 -38
  286. data/lib/barometer/web_services/weather_id.rb +0 -50
  287. data/lib/barometer/web_services/web_service.rb +0 -29
  288. data/spec/cassettes/Barometer.json +0 -1
  289. data/spec/cassettes/Query.json +0 -1
  290. data/spec/cassettes/Query_Format_Coordinates.json +0 -1
  291. data/spec/cassettes/Query_Format_Geocode.json +0 -1
  292. data/spec/cassettes/Query_Format_WeatherID.json +0 -1
  293. data/spec/cassettes/Query_Format_WoeID.json +0 -1
  294. data/spec/cassettes/WeatherService.json +0 -1
  295. data/spec/cassettes/WeatherService_Wunderground.json +0 -1
  296. data/spec/cassettes/WebService_Geocode.json +0 -1
  297. data/spec/cassettes/WebService_NoaaStation.json +0 -1
  298. data/spec/data/local_datetime_spec.rb +0 -274
  299. data/spec/data/local_time_spec.rb +0 -239
  300. data/spec/data/speed_spec.rb +0 -374
  301. data/spec/data/units_spec.rb +0 -101
  302. data/spec/formats/coordinates_spec.rb +0 -166
  303. data/spec/formats/format_spec.rb +0 -74
  304. data/spec/formats/geocode_spec.rb +0 -163
  305. data/spec/formats/icao_spec.rb +0 -55
  306. data/spec/formats/postalcode_spec.rb +0 -53
  307. data/spec/formats/short_zipcode_spec.rb +0 -47
  308. data/spec/formats/weather_id_spec.rb +0 -182
  309. data/spec/formats/woe_id_spec.rb +0 -211
  310. data/spec/formats/zipcode_spec.rb +0 -103
  311. data/spec/key_file_parser_spec.rb +0 -28
  312. data/spec/measurements/measurement_spec.rb +0 -381
  313. data/spec/measurements/result_array_spec.rb +0 -150
  314. data/spec/measurements/result_spec.rb +0 -632
  315. data/spec/query_spec.rb +0 -498
  316. data/spec/weather_services/services_spec.rb +0 -135
  317. data/spec/weather_services/wunderground_spec.rb +0 -179
  318. data/spec/web_services/geocode_spec.rb +0 -31
  319. data/spec/web_services/noaa_station_id_spec.rb +0 -33
  320. data/spec/web_services/placemaker_spec.rb +0 -41
  321. data/spec/web_services/web_services_spec.rb +0 -20
@@ -0,0 +1,22 @@
1
+ require_relative 'query'
2
+
3
+ module Barometer
4
+ module WeatherService
5
+ class ForecastIo
6
+ class Api < Utils::Api
7
+ def initialize(query, api_code)
8
+ @query = ForecastIo::Query.new(query)
9
+ @api_code = api_code
10
+ end
11
+
12
+ def url
13
+ "https://api.forecast.io/forecast/#{@api_code}/#{@query.to_param}"
14
+ end
15
+
16
+ def params
17
+ @query.units_param
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ require 'delegate'
2
+
3
+ module Barometer
4
+ module WeatherService
5
+ class ForecastIo
6
+ class Query < SimpleDelegator
7
+ attr_reader :converted_query
8
+
9
+ def self.accepted_formats
10
+ [:coordinates]
11
+ end
12
+
13
+ def initialize(query)
14
+ super
15
+ @converted_query = convert_query
16
+ end
17
+
18
+ def to_param
19
+ @converted_query.q
20
+ end
21
+
22
+ def units_param
23
+ {units: unit_type}
24
+ end
25
+
26
+ private
27
+
28
+ def convert_query
29
+ convert!(*self.class.accepted_formats)
30
+ end
31
+
32
+ def unit_type
33
+ converted_query.metric? ? 'si' : 'us'
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'response/timezone'
2
+ require_relative 'response/location'
3
+ require_relative 'response/current_weather'
4
+ require_relative 'response/forecasted_weather'
5
+
6
+ module Barometer
7
+ module WeatherService
8
+ class ForecastIo
9
+ class Response
10
+ def initialize
11
+ @response = Barometer::Response.new
12
+ end
13
+
14
+ def parse(payload)
15
+ response.add_query(payload.query)
16
+
17
+ response.timezone = ForecastIo::Response::TimeZone.new(payload).parse
18
+ response.location = ForecastIo::Response::Location.new(payload).parse
19
+ response.current = ForecastIo::Response::CurrentWeather.new(payload).parse
20
+ response.forecast = ForecastIo::Response::ForecastedWeather.new(payload).parse
21
+
22
+ response
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :response
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,78 @@
1
+ module Barometer
2
+ module WeatherService
3
+ class ForecastIo
4
+ class Response
5
+ class CurrentWeather
6
+ def initialize(payload)
7
+ @payload = payload
8
+ @current = Barometer::Response::Current.new
9
+ end
10
+
11
+ def parse
12
+ current.observed_at = observed_at
13
+ current.humidity = humidity
14
+ current.condition = condition
15
+ current.icon = icon
16
+ current.temperature = temperature
17
+ current.dew_point = dew_point
18
+ current.wind = wind
19
+ current.pressure = pressure
20
+ current.visibility = visibility
21
+
22
+ current
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :payload, :current
28
+
29
+ def units
30
+ payload.units
31
+ end
32
+
33
+ def observed_at
34
+ Time.at(payload.fetch('currently', 'time').to_i)
35
+ end
36
+
37
+ def humidity
38
+ payload.fetch('currently', 'humidity') * 100
39
+ end
40
+
41
+ def condition
42
+ payload.fetch('currently', 'summary')
43
+ end
44
+
45
+ def icon
46
+ payload.fetch('currently', 'icon')
47
+ end
48
+
49
+ def temperature
50
+ [units, payload.fetch('currently', 'temperature')]
51
+ end
52
+
53
+ def dew_point
54
+ [units, payload.fetch('currently', 'dewPoint')]
55
+ end
56
+
57
+ def wind
58
+ [units, convert_metre_per_second(payload.fetch('currently', 'windSpeed')), payload.fetch('currently', 'windBearing').to_i]
59
+ end
60
+
61
+ def pressure
62
+ [:metric, payload.fetch('currently', 'pressure')]
63
+ end
64
+
65
+ def visibility
66
+ [units, payload.fetch('currently', 'visibility')]
67
+ end
68
+
69
+ private
70
+
71
+ def convert_metre_per_second(value)
72
+ value.to_f * 60 * 60 / 1000
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,74 @@
1
+ module Barometer
2
+ module WeatherService
3
+ class ForecastIo
4
+ class Response
5
+ class ForecastedWeather
6
+ def initialize(payload)
7
+ @payload = payload
8
+ @predictions = Barometer::Response::PredictionCollection.new
9
+ end
10
+
11
+ def parse
12
+ each_prediction do |prediction, forecast_payload|
13
+ prediction.starts_at = starts_at(forecast_payload)
14
+ prediction.ends_at = Utils::Time.add_one_day(prediction.starts_at)
15
+ prediction.icon = icon(forecast_payload)
16
+ prediction.condition = condition(forecast_payload)
17
+ prediction.high = high(forecast_payload)
18
+ prediction.low = low(forecast_payload)
19
+ prediction.sun = sun(forecast_payload, prediction.starts_at, prediction.ends_at)
20
+ end
21
+
22
+ predictions
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :payload, :predictions
28
+
29
+ def units
30
+ payload.units
31
+ end
32
+
33
+ def each_prediction
34
+ payload.fetch_each('daily', 'data') do |forecast_payload|
35
+ predictions.build do |prediction|
36
+ yield prediction, forecast_payload
37
+ end
38
+ end
39
+ end
40
+
41
+ def starts_at(forecast_payload)
42
+ time(forecast_payload.fetch('time'))
43
+ end
44
+
45
+ def icon(forecast_payload)
46
+ forecast_payload.fetch('icon')
47
+ end
48
+
49
+ def condition(forecast_payload)
50
+ forecast_payload.fetch('summary')
51
+ end
52
+
53
+ def high(forecast_payload)
54
+ [units, forecast_payload.fetch('temperatureMax')]
55
+ end
56
+
57
+ def low(forecast_payload)
58
+ [units, forecast_payload.fetch('temperatureMin')]
59
+ end
60
+
61
+ def sun(forecast_payload, starts_at, ends_at)
62
+ utc_rise_time = time(forecast_payload.fetch('sunriseTime'))
63
+ utc_set_time = time(forecast_payload.fetch('sunsetTime'))
64
+ Data::Sun.new(rise: utc_rise_time, set: utc_set_time)
65
+ end
66
+
67
+ def time(timestamp)
68
+ Time.at(timestamp.to_i)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,19 @@
1
+ module Barometer
2
+ module WeatherService
3
+ class ForecastIo
4
+ class Response
5
+ class Location < WeatherService::Response::Location
6
+ private
7
+
8
+ def latitude
9
+ payload.fetch('latitude')
10
+ end
11
+
12
+ def longitude
13
+ payload.fetch('longitude')
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module Barometer
2
+ module WeatherService
3
+ class ForecastIo
4
+ class Response
5
+ class TimeZone
6
+ def initialize(payload)
7
+ @payload = payload
8
+ end
9
+
10
+ def parse
11
+ Data::Zone.new(time_zone)
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :payload
17
+
18
+ def time_zone
19
+ payload.fetch('timezone')
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,317 +1,33 @@
1
- module Barometer
2
- #
3
- # = NOAA Weather
4
- # http://www.weather.gov/
5
- #
6
- # - key required: NO
7
- # - registration required: NO
8
- # - supported countries: US only
9
- #
10
- # === performs geo coding
11
- # - city: NO
12
- # - coordinates: YES
13
- #
14
- # === time info
15
- # - sun rise/set: NO
16
- # - provides timezone: ?
17
- # - requires TZInfo: ?
18
- #
19
- # == resources
20
- # - API: http://www.weather.gov/forecasts/xml/rest.php
21
- #
22
- # === Possible queries:
23
- # - http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php? \
24
- # format=24%20hourly&numDays=7&zipCodeList=90210
25
- # - http://www.weather.gov/xml/current_obs/KSMO.xml
26
- #
27
- # what query can be:
28
- # - zipcode
29
- # - coordinates
30
- #
31
- # = NOAA terms of use
32
- # see API url provided above
33
- #
34
- class WeatherService::Noaa < WeatherService
35
-
36
- #########################################################################
37
- # PRIVATE
38
- # If class methods could be private, the remaining methods would be.
39
- #
40
-
41
- def self._source_name; :noaa; end
42
- def self._accepted_formats; [:zipcode, :coordinates]; end
43
-
44
- # we can accept US, or we can try if the country is unknown
45
- #
46
- def self._supports_country?(query=nil)
47
- ["US", nil, ""].include?(query.country_code)
48
- end
49
-
50
- def self._build_current(data, metric=true)
51
- raise ArgumentError unless data.is_a?(Hash)
52
-
53
- current = Measurement::Result.new
54
- return current if data.empty?
55
-
56
- if data && data['observation_time_rfc822'] && (time_match = data['observation_time_rfc822'].match(/(.* \d\d:\d\d:\d\d)/))
57
- current.updated_at = Data::LocalDateTime.parse(time_match[1])
58
- end
59
-
60
- current.temperature = Data::Temperature.new(metric)
61
- current.temperature << [data['temp_c'], data['temp_f']]
62
-
63
- current.wind = Data::Speed.new(metric)
64
- current.wind.mph = data['wind_mph'].to_f
65
- current.wind.direction = data['wind_dir']
66
- current.wind.degrees = data['wind_degrees'].to_i
67
-
68
- current.humidity = data['relative_humidity'].to_i
69
-
70
- current.pressure = Data::Pressure.new(metric)
71
- current.pressure << [data['pressure_mb'], data['pressure_in']]
72
-
73
- current.dew_point = Data::Temperature.new(metric)
74
- current.dew_point << [data['dewpoint_c'], data['dewpoint_f']]
75
-
76
- if data['windchill_c'] || data['windchill_f']
77
- current.wind_chill = Data::Temperature.new(metric)
78
- current.wind_chill << [data['windchill_c'], data['windchill_f']]
79
- end
80
-
81
- current.visibility = Data::Distance.new(metric)
82
- current.visibility.m = data['visibility_mi'].to_f
83
-
84
- current.condition = data['weather']
85
- if data['icon_url_name']
86
- icon_match = data['icon_url_name'].match(/(.*).(jpg|png)/)
87
- current.icon = icon_match[1] if icon_match
88
- end
89
-
90
- current
91
- end
92
-
93
- def self._build_forecast(data, metric=true)
94
- raise ArgumentError unless data.is_a?(Hash)
95
-
96
- forecasts = Measurement::ResultArray.new
97
- return forecasts unless data && data['time_layout']
98
-
99
- twelve_hour_starts = []
100
- twelve_hour_ends = []
101
- data['time_layout'].each do |time_layout|
102
- if time_layout["summarization"] == "24hourly"
103
- twelve_hour_starts = time_layout["start_valid_time"]
104
- twelve_hour_ends = time_layout["end_valid_time"]
105
- break
106
- end
107
- end
108
-
109
- daily_highs = []
110
- daily_lows = []
111
- data['parameters']['temperature'].each do |temps|
112
- case temps["type"]
113
- when "maximum"
114
- daily_highs = temps['value']
115
- when "minimum"
116
- daily_lows = temps['value']
117
- end
118
- end
119
-
120
- # NOAA returns 2 pop values for each day ... for each day, use the max pop value
121
- #
122
- daily_pops = []
123
- if data['parameters']['probability_of_precipitation'] &&
124
- data['parameters']['probability_of_precipitation']['value']
125
- daily_pops = data['parameters']['probability_of_precipitation']['value'].collect{|i|i.respond_to?(:to_i) ? i.to_i : 0}.each_slice(2).to_a.collect{|x|x.max}
126
- end
127
-
128
- daily_conditions = []
129
- if data['parameters']['weather'] &&
130
- data['parameters']['weather']['weather_conditions']
131
- daily_conditions = data['parameters']['weather']['weather_conditions'].collect{|c|c["weather_summary"]}
132
- end
133
-
134
- daily_icons = []
135
- if data['parameters']['conditions_icon'] &&
136
- data['parameters']['conditions_icon']['icon_link']
137
- daily_icons = data['parameters']['conditions_icon']['icon_link'].collect{|c|c.match(/.*\/(.*)\.jpg/)[1]}
138
- end
1
+ require_relative 'noaa/forecast_api'
2
+ require_relative 'noaa/forecast_response'
3
+ require_relative 'noaa/current_api'
4
+ require_relative 'noaa/current_response'
139
5
 
140
- d = 0
141
- # go through each forecast start date and create an instance
142
- twelve_hour_starts.each do |start_date|
143
- forecast_measurement = Measurement::Result.new(metric)
144
-
145
- # day = 6am - 6am (next day)
146
- date_s = Date.parse(start_date)
147
- date_e = Date.parse(start_date) + 1
148
- forecast_measurement.valid_start_date = Data::LocalDateTime.new(date_s.year,date_s.month,date_s.day,6,0,0)
149
- forecast_measurement.valid_end_date = Data::LocalDateTime.new(date_e.year,date_e.month,date_e.day,5,59,59)
150
-
151
- forecast_measurement.high = Data::Temperature.new(metric)
152
- forecast_measurement.high.f = (daily_highs[d].respond_to?(:to_f) ? daily_highs[d].to_f : nil)
153
- forecast_measurement.low = Data::Temperature.new(metric)
154
- forecast_measurement.low.f = (daily_lows[d].respond_to?(:to_f) ? daily_lows[d].to_f : nil)
155
-
156
- forecast_measurement.pop = daily_pops[d]
157
- forecast_measurement.condition = daily_conditions[d]
158
- forecast_measurement.icon = daily_icons[d]
159
-
160
- forecasts << forecast_measurement
161
- d += 1
162
- end
163
-
164
- forecasts
165
- end
166
-
167
- def self._build_location(data, geo=nil)
168
- raise ArgumentError unless data.is_a?(Hash)
169
- raise ArgumentError unless (geo.nil? || geo.is_a?(Data::Geo))
170
- location = Data::Location.new
171
- # use the geocoded data if available, otherwise get data from result
172
- if geo
173
- location.city = geo.locality
174
- location.state_code = geo.region
175
- location.country = geo.country
176
- location.country_code = geo.country_code
177
- location.latitude = geo.latitude
178
- location.longitude = geo.longitude
179
- else
180
- if data && data['location']
181
- location.city = data['location'].split(',')[0].strip
182
- location.state_code = data['location'].split(',')[-1].strip
183
- location.country_code = 'US'
184
- end
185
- end
186
- location
187
- end
188
-
189
- def self._build_station(data)
190
- raise ArgumentError unless data.is_a?(Hash)
191
- station = Data::Location.new
192
- station.id = data['station_id']
193
- if data['location']
194
- station.name = data['location']
195
- station.city = data['location'].split(',')[0].strip
196
- station.state_code = data['location'].split(',')[-1].strip
197
- station.country_code = 'US'
198
- station.latitude = data['latitude']
199
- station.longitude = data['longitude']
200
- end
201
- station
202
- end
203
-
204
- def self._build_timezone(data)
205
- if data && data['observation_time']
206
- zone_match = data['observation_time'].match(/ ([A-Z]*)$/)
207
- Data::Zone.new(zone_match[1]) if zone_match
208
- end
209
- end
210
-
211
- # override default _fetch behavior
212
- # this service requires TWO seperate http requests (one for current
213
- # and one for forecasted weather) ... combine the results
214
- #
215
- def self._fetch(query, metric=true)
216
- result = []
217
- result << _fetch_forecast(query,metric)
218
-
219
- # only proceed if we are getting results
220
- #
221
- # binding.pry
222
- if result[0] && !result[0].empty?
223
- # we need to use the lst/long from the forecast data (result[0])
224
- # to get the closest "station_id", to get the current conditions
225
- #
226
- station_id = Barometer::WebService::NoaaStation.fetch(
227
- result[0]["location"]["point"]["latitude"],
228
- result[0]["location"]["point"]["longitude"]
229
- )
230
-
231
- result << _fetch_current(station_id,metric)
232
- else
233
- puts "NOAA cannot proceed to fetching current weather, lat/lon unknown" if Barometer::debug?
234
- result << {}
6
+ module Barometer
7
+ module WeatherService
8
+ class Noaa
9
+ def self.call(query, config={})
10
+ Noaa.new(query).measure!
235
11
  end
236
12
 
237
- result
238
- end
239
-
240
- # use HTTParty to get the current weather
241
- #
242
- def self._fetch_current(station_id, metric=true)
243
- return {} unless station_id
244
- puts "fetching NOAA current weather: #{station_id}" if Barometer::debug?
245
-
246
- self.get(
247
- "http://w1.weather.gov/xml/current_obs/#{station_id}.xml",
248
- :query => {},
249
- :format => :xml,
250
- :timeout => Barometer.timeout
251
- )["current_observation"]
252
- end
253
-
254
- # use HTTParty to get the forecasted weather
255
- #
256
- def self._fetch_forecast(query, metric=true)
257
- puts "fetching NOAA forecast: #{query.q}" if Barometer::debug?
258
-
259
- q = case query.format.to_sym
260
- when :short_zipcode
261
- { :zipCodeList => query.q }
262
- when :zipcode
263
- { :zipCodeList => query.q }
264
- when :coordinates
265
- { :lat => query.q.split(',')[0], :lon => query.q.split(',')[1] }
266
- else
267
- {}
13
+ def initialize(query)
14
+ @query = query
268
15
  end
269
16
 
270
- result = self.get(
271
- "http://graphical.weather.gov/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php",
272
- :query => {
273
- :format => "24 hourly",
274
- :numDays => "7"
275
- }.merge(q),
276
- :format => :xml,
277
- :timeout => Barometer.timeout
278
- )
279
-
17
+ def measure!
18
+ forecast_weather_api = ForecastApi.new(query)
19
+ response = ForecastResponse.new.parse(forecast_weather_api.get)
20
+ forecast_weather_api.query.add_conversion(:coordinates, response.location.coordinates)
280
21
 
281
- # binding.pry
282
-
283
- if result && result["dwml"] && result["dwml"]["data"]
284
- result = result["dwml"]["data"]
285
- else
286
- return {}
22
+ current_weather_api = CurrentApi.new(forecast_weather_api.query)
23
+ CurrentResponse.new(response).parse(current_weather_api.get)
287
24
  end
288
25
 
289
- # check that we have data ... we have to dig deep to find out since
290
- # NOAA will return a good looking result, even when there isn't any data to return
291
- #
292
- if result && result['parameters'] &&
293
- result['parameters']['temperature'] &&
294
- result['parameters']['temperature'].first &&
295
- result['parameters']['temperature'].first['value'] &&
296
- !result['parameters']['temperature'].first['value'].collect{|t| t.respond_to?(:to_i) ? t.to_i : nil}.compact.empty?
297
- else
298
- return {}
299
- end
26
+ private
300
27
 
301
- result
28
+ attr_reader :query
302
29
  end
303
-
304
- # since we have two sets of data, override these calls to choose the
305
- # right set of data
306
- #
307
- def self._current_result(data); data[1]; end
308
- def self._forecast_result(data=nil); data[0]; end
309
- def self._location_result(data=nil); data[1]; end
310
- def self._station_result(data=nil); data[1]; end
311
- def self._sun_result(data=nil); nil; end
312
- def self._timezone_result(data=nil); data[1]; end
313
- def self._time_result(data=nil); data[1]; end
314
-
315
30
  end
316
-
317
31
  end
32
+
33
+ Barometer::WeatherService.register(:noaa, Barometer::WeatherService::Noaa)