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
@@ -1,141 +1,138 @@
1
- require 'rubygems'
2
1
  require 'tzinfo'
2
+ require 'delegate'
3
3
 
4
4
  module Barometer
5
- #
6
- # A simple Zone class
7
- #
8
- # Used for building and converting timezone aware date and times
9
- # Really, these are just wrappers for TZInfo conversions plus
10
- # some extras.
11
- #
12
- class Data::Zone
13
-
14
- @@zone_codes_file = File.expand_path(
15
- File.join(File.dirname(__FILE__), '..', 'translations', 'zone_codes.yml'))
16
- @@zone_codes = nil
17
-
18
- attr_accessor :zone_full, :zone_code, :zone_offset, :tz
19
-
20
- def initialize(zone)
21
- if Data::Zone.is_zone_full?(zone)
22
- @zone_full = zone
23
- @tz = TZInfo::Timezone.get(zone)
24
- elsif Data::Zone.is_zone_offset?(zone)
25
- @zone_offset = zone
26
- elsif Data::Zone.is_zone_code?(zone)
27
- @zone_code = zone
28
- else
29
- raise(ArgumentError, "invalid time zone")
5
+ module Data
6
+ class Zone < SimpleDelegator
7
+ def initialize(zone)
8
+ zone = if ZoneFull.detect?(zone)
9
+ ZoneFull.new(zone)
10
+ elsif ZoneOffset.detect?(zone)
11
+ ZoneOffset.new(zone)
12
+ elsif ZoneCode.detect?(zone)
13
+ ZoneCode.new(zone)
14
+ else
15
+ raise(ArgumentError, "invalid time zone")
16
+ end
17
+ super(zone)
30
18
  end
31
19
  end
32
20
 
33
- def current
34
- @zone_full || @zone_offset || @zone_code
35
- end
21
+ class ZoneFull
22
+ def self.detect?(zone)
23
+ zone.respond_to?(:match) && !!zone.match(/^[A-Za-z]+\/[A-Za-z_]+$/)
24
+ end
36
25
 
37
- # what is the Timezone Short Code for the current timezone
38
- def code
39
- return @zone_code if @zone_code
40
- return nil unless @tz
41
- @tz.period_for_utc(Time.now.utc).zone_identifier.to_s
42
- end
26
+ def initialize(zone, time_class=::Time)
27
+ @zone = zone
28
+ @time_class = time_class
29
+ @tz = TZInfo::Timezone.get(zone)
30
+ end
43
31
 
44
- def full
45
- @zone_full || nil
46
- end
32
+ def code
33
+ tz.period_for_utc(time_class.now.utc).zone_identifier.to_s
34
+ end
47
35
 
48
- def offset
49
- if @zone_offset
50
- @zone_offset.to_f * 60 * 60
51
- elsif @zone_code
52
- Data::Zone.zone_to_offset(@zone_code)
53
- elsif @zone_full
36
+ def offset
37
+ tz.period_for_utc(time_class.now.utc).utc_total_offset
54
38
  end
55
- end
56
39
 
57
- # is the current timezone in daylights savings mode?
58
- def dst?
59
- return nil unless @tz
60
- @tz.period_for_utc(Time.now.utc).dst?
61
- end
40
+ def now
41
+ tz.utc_to_local(time_class.now.utc)
42
+ end
62
43
 
63
- # return Time.now.utc for the set timezone
64
- def now(convert=false)
65
- if @zone_full
66
- now = @tz.utc_to_local(Time.now.utc)
67
- elsif @zone_offset || @zone_code
68
- now = Time.now.utc + self.offset
44
+ def to_s
45
+ zone
69
46
  end
70
- convert ? Data::LocalTime.parse(now) : now
71
- end
72
47
 
73
- # return Date.today for the set timezone
74
- def today
75
- now = self.now
76
- Date.new(now.year, now.month, now.day)
77
- end
48
+ def local_to_utc(local_time)
49
+ tz.local_to_utc(local_time)
50
+ end
78
51
 
79
- def local_to_utc(local_time)
80
- if @zone_full
81
- @tz.local_to_utc(local_time)
82
- elsif @zone_offset || @zone_code
83
- local_time -= self.offset
84
- Time.utc(local_time.year,local_time.month,local_time.day,
85
- local_time.hour,local_time.min,local_time.sec)
52
+ def utc_to_local(utc_time)
53
+ tz.utc_to_local(utc_time)
86
54
  end
55
+
56
+ private
57
+
58
+ attr_reader :zone, :tz, :time_class
87
59
  end
88
60
 
89
- def utc_to_local(utc_time)
90
- if @zone_full
91
- @tz.utc_to_local(utc_time)
92
- elsif @zone_offset || @zone_code
93
- utc_time + self.offset
61
+ class ZoneOffset
62
+ def self.detect?(zone)
63
+ zone.respond_to?(:abs) && zone.abs <= 14
94
64
  end
95
- end
96
65
 
97
- #
98
- # Class Methods
99
- #
66
+ def initialize(zone, time_class=::Time)
67
+ @zone = zone
68
+ @time_class = time_class
69
+ end
100
70
 
101
- def self.is_zone_code?(zone)
102
- return false unless (zone && zone.is_a?(String))
103
- _load_zone_codes unless @@zone_codes
104
- Time.zone_offset(zone) || (@@zone_codes && @@zone_codes.has_key?(zone))
105
- end
71
+ def code
72
+ end
106
73
 
107
- def self.is_zone_full?(zone)
108
- return false unless (zone && zone.is_a?(String))
109
- zone.match(/[A-Za-z]+\/[A-Za-z]+/) ? true : false
110
- end
74
+ def offset
75
+ zone.to_f * 60 * 60
76
+ end
111
77
 
112
- def self.is_zone_offset?(zone)
113
- return false unless (zone && (zone.is_a?(Fixnum) || zone.is_a?(Float)))
114
- zone.to_f.abs <= 14
115
- end
78
+ def now
79
+ time_class.now.utc + offset
80
+ end
116
81
 
117
- #
118
- # Known conflicts
119
- # IRT (ireland and india)
120
- # CST (central standard time, china standard time)
121
- #
122
- def self.zone_to_offset(timezone)
123
- offset = 0
124
- seconds_in_hour = 60*60
125
- # try to use Time
126
- unless offset = Time.zone_offset(timezone)
127
- # that would have been too easy, do it manually
128
- # http://www.timeanddate.com/library/abbreviations/timezones/
129
- # http://www.worldtimezone.com/wtz-names/timezonenames.html
130
- offset = (@@zone_codes[timezone.to_s.upcase] || 0) * seconds_in_hour
131
- end
132
- offset
133
- end
82
+ def to_s
83
+ zone.to_s
84
+ end
85
+
86
+ def local_to_utc(local_time)
87
+ local_time - offset
88
+ end
89
+
90
+ def utc_to_local(utc_time)
91
+ utc_time + offset
92
+ end
93
+
94
+ private
134
95
 
135
- def self._load_zone_codes
136
- $:.unshift(File.dirname(__FILE__))
137
- @@zone_codes ||= YAML.load_file(@@zone_codes_file)
96
+ attr_reader :zone, :time_class
138
97
  end
139
98
 
99
+ class ZoneCode
100
+ def self.detect?(zone)
101
+ zone.respond_to?(:to_s) && Utils::ZoneCodeLookup.exists?(zone.to_s)
102
+ end
103
+
104
+ def initialize(zone, time_class=::Time)
105
+ @zone = zone
106
+ @time_class = time_class
107
+ end
108
+
109
+ def code
110
+ zone
111
+ end
112
+
113
+ def offset
114
+ Utils::ZoneCodeLookup.offset(zone)
115
+ end
116
+
117
+ def now
118
+ time_class.now.utc + offset
119
+ end
120
+
121
+ def to_s
122
+ zone
123
+ end
124
+
125
+ def local_to_utc(local_time)
126
+ local_time - offset
127
+ end
128
+
129
+ def utc_to_local(utc_time)
130
+ utc_time + offset
131
+ end
132
+
133
+ private
134
+
135
+ attr_reader :zone, :time_class
136
+ end
140
137
  end
141
138
  end
@@ -1,172 +1,34 @@
1
- module Barometer
2
- #
3
- # This class represents a query and can answer the
4
- # questions that a Barometer will need to measure the weather
5
- #
6
- # Summary:
7
- # When you create a new Query, you set the query string
8
- # ie: "New York, NY" or "90210"
9
- # The class will then determine the query string format
10
- # ie: :zipcode, :postalcode, :geocode, :coordinates
11
- # Now, when a Weather API driver asks for the query, it will prefer
12
- # certain formats, and only permit certain formats. The Query class
13
- # will attempt to either return the query string as-is if acceptable,
14
- # or it will attempt to convert it to a format that is acceptable
15
- # (most likely this conversion will use Googles geocoding service using
16
- # the Graticule gem). Worst case scenario is that the Weather API will
17
- # not accept the query string.
18
- #
19
- class Query
20
-
21
- # This array defines the order to check a query for the format
22
- #
23
- FORMATS = %w(
24
- ShortZipcode Zipcode Postalcode WeatherID Coordinates Icao WoeID Geocode
25
- )
26
- FORMAT_MAP = {
27
- :short_zipcode => "ShortZipcode", :zipcode => "Zipcode",
28
- :postalcode => "Postalcode", :weather_id => "WeatherID",
29
- :coordinates => "Coordinates", :icao => "Icao",
30
- :woe_id => "WoeID", :geocode => "Geocode"
31
- }
32
-
33
- attr_writer :q
34
- attr_accessor :format, :country_code
35
- attr_accessor :geo, :timezone, :conversions
1
+ require_relative 'query/base'
2
+ require_relative 'query/format'
3
+ require_relative 'query/converter'
4
+ require_relative 'query/service'
36
5
 
37
- def initialize(query=nil)
38
- return unless query
39
- @q = query
40
- self.analyze!
41
- @conversions = {}
6
+ module Barometer
7
+ class ConvertedQuery
8
+ attr_reader :q, :format, :units, :geo
9
+
10
+ def initialize(q, format, units=:metric, geo=nil)
11
+ @q = q
12
+ @format = format
13
+ @units = units
14
+ @geo = geo
42
15
  end
43
16
 
44
- def q
45
- format ? Barometer::Query::Format.const_get(FORMAT_MAP[format.to_sym].to_s).convert_query(@q) : @q
17
+ def metric?
18
+ units == :metric
46
19
  end
47
20
 
48
- # analyze the saved query to determine the format.
49
- # this delegates the detection to each formats class
50
- # until th right one is found
51
- #
52
- def analyze!
53
- return unless @q
54
- FORMATS.each do |format|
55
- if Query::Format.const_get(format.to_s).is?(@q)
56
- @format = Query::Format.const_get(format.to_s).format
57
- @country_code = Query::Format.const_get(format.to_s).country_code(@q)
58
- break
59
- end
60
- end
21
+ def to_s
22
+ @q
61
23
  end
62
-
63
- # take a list of acceptable (and ordered by preference) formats and convert
64
- # the current query (q) into the most preferred and acceptable format. a
65
- # side effect of the conversions may reveal the country_code, if so save it
66
- #
67
- def convert!(preferred_formats=nil)
68
- raise ArgumentError unless (preferred_formats && preferred_formats.size > 0)
69
-
70
- # why convert if we are already there?
71
- # (except in the case that the serivce excepts coordinates and we have a
72
- # a geocode ... the google geocode results are superior)
73
- #
74
- skip_conversion = false
75
- unless (@format.to_sym == Query::Format::Geocode.format) &&
76
- preferred_formats.include?(Query::Format::Coordinates.format)
77
- if preferred_formats.include?(@format.to_sym)
78
- skip_conversion = true
79
- converted_query = self.dup
80
- end
81
- end
82
-
83
- unless skip_conversion
84
- # go through each acceptable format and try to convert to that
85
- converted = false
86
- converted_query = Barometer::Query.new
87
- preferred_formats.each do |preferred_format|
88
- klass = FORMAT_MAP[preferred_format.to_sym]
89
- # if we discover that the format we have is the preferred format, return it
90
- if preferred_format == @format
91
- converted = true
92
- converted_query = Barometer::Query.new(@q)
93
- end
94
- unless converted
95
- unless converted_query = get_conversion(preferred_format)
96
- converted_query = Query::Format.const_get(klass.to_s).to(self)
97
- end
98
- converted = true if converted_query
99
- end
100
- if converted
101
- converted_query.country_code ||= Query::Format.const_get(klass.to_s).country_code(converted_query.q)
102
- post_conversion(converted_query)
103
- break
104
- end
105
- end
106
- end
107
-
108
- # force geocode?, unless we already did
109
- #
110
- if Barometer.force_geocode && !@geo
111
- if converted_query && converted_query.geo
112
- @geo = converted_query.geo
113
- elsif converted_query
114
- puts "enhance geocode: #{converted_query.q}" if Barometer::debug?
115
- geo_query = Query::Format::Coordinates.to(converted_query)
116
- @geo = geo_query.geo if (geo_query && geo_query.geo)
117
- converted_query.geo = @geo.dup
118
- end
119
- end
120
-
121
- # enhance timezone?, unless we already did
122
- #
123
- if Barometer.enhance_timezone && !@timezone
124
- if converted_query && converted_query.timezone
125
- @geo = converted_query.timezone
126
- elsif @geo && @geo.latitude && @geo.longitude
127
- puts "enhance timezone: #{@geo.latitude}, #{@geo.longitude}" if Barometer::debug?
128
- @timezone = WebService::Timezone.fetch(@geo.latitude,@geo.longitude)
129
- converted_query.timezone = @timezone.dup
130
- end
131
- end
132
-
133
- converted_query
134
- end
135
-
136
- # save the important parts of the conversion ... by saving conversion we
137
- # can avoid doing the same conversion multiple times
138
- #
139
- def post_conversion(converted_query)
140
- return unless (converted_query && converted_query.q && converted_query.format)
141
- @conversions = {} unless @conversions
142
- return if @conversions.has_key?(converted_query.format.to_sym)
143
- puts "store: #{self.format} -> #{converted_query.format.to_sym} = #{self.q} -> #{converted_query.q}" if Barometer::debug?
144
- @conversions[converted_query.format.to_sym] = converted_query.q
145
- end
146
-
147
- def get_conversion(format)
148
- return nil unless format && @conversions
149
- puts "found: #{self.format} -> #{format.to_sym} = #{self.q} -> #{@conversions[format.to_sym]}" if Barometer::debug? && @conversions.has_key?(format.to_sym)
150
- # re-constuct converted query
151
- if q = @conversions[format.to_sym]
152
- converted_query = self.dup
153
- converted_query.q = q
154
- converted_query.format = format
155
- converted_query
156
- else
157
- nil
158
24
  end
159
- end
160
25
 
161
- def latitude
162
- return nil unless self.format == Query::Format::Coordinates.format
163
- Query::Format::Coordinates.parse_latitude(self.q)
164
- end
165
-
166
- def longitude
167
- return nil unless self.format == Query::Format::Coordinates.format
168
- Query::Format::Coordinates.parse_longitude(self.q)
169
- end
26
+ module Query
27
+ class ConversionNotPossible < StandardError; end
28
+ class UnsupportedRegion < StandardError; end
170
29
 
30
+ def self.new(*args)
31
+ Barometer::Query::Base.new(*args)
32
+ end
171
33
  end
172
34
  end
@@ -0,0 +1,88 @@
1
+ module Barometer
2
+ module Query
3
+ class Base
4
+ attr_reader :format, :geo, :units
5
+
6
+ def initialize(query, units=:metric)
7
+ @q = query.dup
8
+ @units = units
9
+ @geo = Data::Geo.new
10
+ detect_format
11
+ freeze_query
12
+ @conversions = {}
13
+ end
14
+
15
+ def q
16
+ @format_klass.convert_query(@q)
17
+ end
18
+
19
+ def add_conversion(format, q)
20
+ return unless q
21
+
22
+ @conversions[format] = q
23
+ converted_query(q, format)
24
+ end
25
+
26
+ def get_conversion(*formats)
27
+ converted_format = formats.detect{|f| format == f || @conversions.has_key?(f)}
28
+ return unless converted_format
29
+
30
+ if converted_format == format
31
+ self
32
+ else
33
+ converted_query(@conversions[converted_format], converted_format)
34
+ end
35
+ end
36
+
37
+ def convert!(*preferred_formats)
38
+ return self if preferred_formats.include?(format)
39
+
40
+ get_conversion(*preferred_formats) ||
41
+ do_conversion(format, preferred_formats) ||
42
+ raise(ConversionNotPossible)
43
+ end
44
+
45
+ def metric?
46
+ units == :metric
47
+ end
48
+
49
+ def to_s
50
+ q.to_s
51
+ end
52
+
53
+ def geo=(geo)
54
+ @geo = @geo.merge(geo)
55
+ end
56
+
57
+ private
58
+
59
+ def converted_query(q, format)
60
+ ConvertedQuery.new(q, format, units, geo)
61
+ end
62
+
63
+ def detect_format
64
+ Format.match?(@q) do |key, klass|
65
+ @format = key
66
+ @geo = Data::Geo.new(country_code: klass.country_code(@q))
67
+ @format_klass = klass
68
+ end
69
+ end
70
+
71
+ def freeze_query
72
+ @q.freeze
73
+ @format.freeze
74
+ @units.freeze
75
+ end
76
+
77
+ def do_conversion(format, preferred_formats)
78
+ converters = Converter.find_all(format, preferred_formats)
79
+ result = converters.map do |converter|
80
+ to_format = converter.keys.first
81
+ converter_klass = converter.values.first
82
+ get_conversion(to_format) || converter_klass.new(self).call
83
+ end.last
84
+ get_conversion(*preferred_formats) || result
85
+ end
86
+ end
87
+ end
88
+ end