barometer 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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)