barometer 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +7 -0
  3. data/LICENSE +1 -1
  4. data/{README.rdoc → README.md} +124 -110
  5. data/Rakefile +1 -21
  6. data/TODO +8 -9
  7. data/barometer.gemspec +20 -19
  8. data/bin/barometer +36 -83
  9. data/lib/barometer.rb +13 -11
  10. data/lib/barometer/base.rb +10 -10
  11. data/lib/barometer/data.rb +1 -1
  12. data/lib/barometer/data/distance.rb +25 -25
  13. data/lib/barometer/data/geo.rb +9 -9
  14. data/lib/barometer/data/local_datetime.rb +24 -20
  15. data/lib/barometer/data/local_time.rb +13 -13
  16. data/lib/barometer/data/location.rb +6 -6
  17. data/lib/barometer/data/pressure.rb +24 -24
  18. data/lib/barometer/data/speed.rb +28 -28
  19. data/lib/barometer/data/sun.rb +7 -7
  20. data/lib/barometer/data/temperature.rb +29 -29
  21. data/lib/barometer/data/units.rb +9 -9
  22. data/lib/barometer/data/zone.rb +19 -19
  23. data/lib/barometer/formats.rb +1 -1
  24. data/lib/barometer/formats/coordinates.rb +7 -7
  25. data/lib/barometer/formats/format.rb +6 -6
  26. data/lib/barometer/formats/geocode.rb +5 -5
  27. data/lib/barometer/formats/icao.rb +6 -6
  28. data/lib/barometer/formats/postalcode.rb +3 -3
  29. data/lib/barometer/formats/short_zipcode.rb +2 -2
  30. data/lib/barometer/formats/weather_id.rb +10 -10
  31. data/lib/barometer/formats/woe_id.rb +20 -20
  32. data/lib/barometer/formats/zipcode.rb +3 -3
  33. data/lib/barometer/key_file_parser.rb +20 -0
  34. data/lib/barometer/measurements/measurement.rb +32 -32
  35. data/lib/barometer/measurements/result.rb +39 -39
  36. data/lib/barometer/measurements/result_array.rb +12 -12
  37. data/lib/barometer/query.rb +15 -15
  38. data/lib/barometer/services.rb +3 -3
  39. data/lib/barometer/translations/icao_country_codes.yml +20 -20
  40. data/lib/barometer/translations/weather_country_codes.yml +1 -1
  41. data/lib/barometer/translations/zone_codes.yml +2 -2
  42. data/lib/barometer/version.rb +3 -0
  43. data/lib/barometer/weather.rb +27 -27
  44. data/lib/barometer/weather_services/noaa.rb +314 -3
  45. data/lib/barometer/weather_services/service.rb +32 -30
  46. data/lib/barometer/weather_services/weather_bug.rb +35 -33
  47. data/lib/barometer/weather_services/wunderground.rb +31 -29
  48. data/lib/barometer/weather_services/yahoo.rb +36 -35
  49. data/lib/barometer/web_services/geocode.rb +5 -7
  50. data/lib/barometer/web_services/noaa_station_id.rb +53 -0
  51. data/lib/barometer/web_services/placemaker.rb +11 -13
  52. data/lib/barometer/web_services/timezone.rb +5 -7
  53. data/lib/barometer/web_services/weather_id.rb +4 -6
  54. data/lib/barometer/web_services/web_service.rb +4 -4
  55. data/spec/barometer_spec.rb +25 -27
  56. data/spec/cassettes/Barometer.json +1 -0
  57. data/spec/cassettes/Query.json +1 -0
  58. data/spec/cassettes/Query_Format_Coordinates.json +1 -0
  59. data/spec/cassettes/Query_Format_Geocode.json +1 -0
  60. data/spec/cassettes/Query_Format_WeatherID.json +1 -0
  61. data/spec/cassettes/Query_Format_WoeID.json +1 -0
  62. data/spec/cassettes/WeatherService.json +1 -0
  63. data/spec/cassettes/WeatherService_Noaa.json +1 -0
  64. data/spec/cassettes/WeatherService_WeatherBug.json +1 -0
  65. data/spec/cassettes/WeatherService_Wunderground.json +1 -0
  66. data/spec/cassettes/WeatherService_Yahoo.json +1 -0
  67. data/spec/cassettes/WebService_Geocode.json +1 -0
  68. data/spec/cassettes/WebService_NoaaStation.json +1 -0
  69. data/spec/data/distance_spec.rb +60 -60
  70. data/spec/data/geo_spec.rb +23 -23
  71. data/spec/data/local_datetime_spec.rb +44 -44
  72. data/spec/data/local_time_spec.rb +47 -47
  73. data/spec/data/location_spec.rb +16 -16
  74. data/spec/data/pressure_spec.rb +61 -61
  75. data/spec/data/speed_spec.rb +69 -69
  76. data/spec/data/sun_spec.rb +25 -25
  77. data/spec/data/temperature_spec.rb +68 -68
  78. data/spec/data/units_spec.rb +21 -21
  79. data/spec/data/zone_spec.rb +35 -35
  80. data/spec/formats/coordinates_spec.rb +27 -27
  81. data/spec/formats/format_spec.rb +17 -25
  82. data/spec/formats/geocode_spec.rb +23 -31
  83. data/spec/formats/icao_spec.rb +26 -32
  84. data/spec/formats/postalcode_spec.rb +22 -28
  85. data/spec/formats/short_zipcode_spec.rb +20 -26
  86. data/spec/formats/weather_id_spec.rb +57 -67
  87. data/spec/formats/woe_id_spec.rb +59 -59
  88. data/spec/formats/zipcode_spec.rb +39 -47
  89. data/spec/key_file_parser_spec.rb +28 -0
  90. data/spec/measurements/measurement_spec.rb +79 -133
  91. data/spec/measurements/result_array_spec.rb +23 -38
  92. data/spec/measurements/result_spec.rb +100 -128
  93. data/spec/query_spec.rb +83 -100
  94. data/spec/spec_helper.rb +24 -6
  95. data/spec/weather_services/noaa_spec.rb +179 -0
  96. data/spec/weather_services/services_spec.rb +28 -36
  97. data/spec/weather_services/weather_bug_spec.rb +57 -77
  98. data/spec/weather_services/wunderground_spec.rb +36 -65
  99. data/spec/weather_services/yahoo_spec.rb +38 -60
  100. data/spec/weather_spec.rb +79 -79
  101. data/spec/web_services/geocode_spec.rb +7 -11
  102. data/spec/web_services/noaa_station_id_spec.rb +33 -0
  103. data/spec/web_services/placemaker_spec.rb +7 -12
  104. data/spec/web_services/web_services_spec.rb +3 -9
  105. metadata +214 -163
  106. data/VERSION.yml +0 -5
  107. data/lib/barometer/weather_services/google.rb +0 -142
  108. data/lib/barometer/weather_services/weather_dot_com.rb +0 -279
  109. data/spec/fakeweb_helper.rb +0 -179
  110. data/spec/fixtures/formats/weather_id/90210.xml +0 -7
  111. data/spec/fixtures/formats/weather_id/from_USGA0028.xml +0 -3
  112. data/spec/fixtures/formats/weather_id/ksfo.xml +0 -1
  113. data/spec/fixtures/formats/weather_id/manhattan.xml +0 -7
  114. data/spec/fixtures/formats/weather_id/new_york.xml +0 -1
  115. data/spec/fixtures/formats/weather_id/the_hills.xml +0 -1
  116. data/spec/fixtures/geocode/40_73_v3.json +0 -497
  117. data/spec/fixtures/geocode/90210_v3.json +0 -63
  118. data/spec/fixtures/geocode/T5B4M9_v3.json +0 -68
  119. data/spec/fixtures/geocode/atlanta_v3.json +0 -58
  120. data/spec/fixtures/geocode/calgary_ab_v3.json +0 -58
  121. data/spec/fixtures/geocode/ksfo_v3.json +0 -73
  122. data/spec/fixtures/geocode/newyork_ny_v3.json +0 -58
  123. data/spec/fixtures/services/google/calgary_ab.xml +0 -1
  124. data/spec/fixtures/services/placemaker/T5B4M9.xml +0 -65
  125. data/spec/fixtures/services/placemaker/atlanta.xml +0 -65
  126. data/spec/fixtures/services/placemaker/coords.xml +0 -65
  127. data/spec/fixtures/services/placemaker/ksfo.xml +0 -65
  128. data/spec/fixtures/services/placemaker/new_york.xml +0 -65
  129. data/spec/fixtures/services/placemaker/the_hills.xml +0 -65
  130. data/spec/fixtures/services/placemaker/w615702.xml +0 -47
  131. data/spec/fixtures/services/weather_bug/90210_current.xml +0 -93
  132. data/spec/fixtures/services/weather_bug/90210_forecast.xml +0 -76
  133. data/spec/fixtures/services/weather_dot_com/90210.xml +0 -1
  134. data/spec/fixtures/services/wunderground/current_calgary_ab.xml +0 -9
  135. data/spec/fixtures/services/wunderground/forecast_calgary_ab.xml +0 -13
  136. data/spec/fixtures/services/yahoo/90210.xml +0 -3
  137. data/spec/weather_services/google_spec.rb +0 -181
  138. data/spec/weather_services/weather_dot_com_spec.rb +0 -224
@@ -1,15 +1,15 @@
1
1
  module Barometer
2
2
  class Data::Units
3
3
  include Comparable
4
-
4
+
5
5
  attr_accessor :metric
6
-
6
+
7
7
  def initialize(metric=true); @metric = metric; end
8
-
8
+
9
9
  #
10
10
  # HELPERS
11
11
  #
12
-
12
+
13
13
  def metric?; @metric; end
14
14
  def metric!; @metric=true; end
15
15
  def imperial!; @metric=false; end
@@ -18,10 +18,10 @@ module Barometer
18
18
  #
19
19
  def <<(value)
20
20
  return unless value
21
-
21
+
22
22
  # these values can be treated like 'nil'
23
23
  nil_values = ["NA", "N/A", ""]
24
-
24
+
25
25
  begin
26
26
  if value.is_a?(Array)
27
27
  value_m = value[0].to_f if (value[0] && !nil_values.include?(value[0]))
@@ -35,15 +35,15 @@ module Barometer
35
35
  rescue
36
36
  # do nothing
37
37
  end
38
-
38
+
39
39
  self.metric? ? self.metric_default = value_m || value_b :
40
40
  self.imperial_default = value_i || value_b
41
41
  end
42
-
42
+
43
43
  # stubs
44
44
  #
45
45
  def metric_default=(value); raise NotImplementedError; end
46
46
  def imperial_default=(value); raise NotImplementedError; end
47
47
 
48
48
  end
49
- end
49
+ end
@@ -4,19 +4,19 @@ require 'tzinfo'
4
4
  module Barometer
5
5
  #
6
6
  # A simple Zone class
7
- #
7
+ #
8
8
  # Used for building and converting timezone aware date and times
9
9
  # Really, these are just wrappers for TZInfo conversions plus
10
10
  # some extras.
11
11
  #
12
12
  class Data::Zone
13
-
13
+
14
14
  @@zone_codes_file = File.expand_path(
15
15
  File.join(File.dirname(__FILE__), '..', 'translations', 'zone_codes.yml'))
16
16
  @@zone_codes = nil
17
17
 
18
18
  attr_accessor :zone_full, :zone_code, :zone_offset, :tz
19
-
19
+
20
20
  def initialize(zone)
21
21
  if Data::Zone.is_zone_full?(zone)
22
22
  @zone_full = zone
@@ -29,22 +29,22 @@ module Barometer
29
29
  raise(ArgumentError, "invalid time zone")
30
30
  end
31
31
  end
32
-
32
+
33
33
  def current
34
34
  @zone_full || @zone_offset || @zone_code
35
35
  end
36
-
36
+
37
37
  # what is the Timezone Short Code for the current timezone
38
38
  def code
39
39
  return @zone_code if @zone_code
40
40
  return nil unless @tz
41
41
  @tz.period_for_utc(Time.now.utc).zone_identifier.to_s
42
42
  end
43
-
43
+
44
44
  def full
45
45
  @zone_full || nil
46
46
  end
47
-
47
+
48
48
  def offset
49
49
  if @zone_offset
50
50
  @zone_offset.to_f * 60 * 60
@@ -53,13 +53,13 @@ module Barometer
53
53
  elsif @zone_full
54
54
  end
55
55
  end
56
-
56
+
57
57
  # is the current timezone in daylights savings mode?
58
58
  def dst?
59
59
  return nil unless @tz
60
60
  @tz.period_for_utc(Time.now.utc).dst?
61
61
  end
62
-
62
+
63
63
  # return Time.now.utc for the set timezone
64
64
  def now(convert=false)
65
65
  if @zone_full
@@ -69,13 +69,13 @@ module Barometer
69
69
  end
70
70
  convert ? Data::LocalTime.parse(now) : now
71
71
  end
72
-
72
+
73
73
  # return Date.today for the set timezone
74
74
  def today
75
75
  now = self.now
76
76
  Date.new(now.year, now.month, now.day)
77
77
  end
78
-
78
+
79
79
  def local_to_utc(local_time)
80
80
  if @zone_full
81
81
  @tz.local_to_utc(local_time)
@@ -85,7 +85,7 @@ module Barometer
85
85
  local_time.hour,local_time.min,local_time.sec)
86
86
  end
87
87
  end
88
-
88
+
89
89
  def utc_to_local(utc_time)
90
90
  if @zone_full
91
91
  @tz.utc_to_local(utc_time)
@@ -93,22 +93,22 @@ module Barometer
93
93
  utc_time + self.offset
94
94
  end
95
95
  end
96
-
96
+
97
97
  #
98
98
  # Class Methods
99
99
  #
100
-
100
+
101
101
  def self.is_zone_code?(zone)
102
102
  return false unless (zone && zone.is_a?(String))
103
103
  _load_zone_codes unless @@zone_codes
104
104
  Time.zone_offset(zone) || (@@zone_codes && @@zone_codes.has_key?(zone))
105
105
  end
106
-
106
+
107
107
  def self.is_zone_full?(zone)
108
108
  return false unless (zone && zone.is_a?(String))
109
109
  zone.match(/[A-Za-z]+\/[A-Za-z]+/) ? true : false
110
110
  end
111
-
111
+
112
112
  def self.is_zone_offset?(zone)
113
113
  return false unless (zone && (zone.is_a?(Fixnum) || zone.is_a?(Float)))
114
114
  zone.to_f.abs <= 14
@@ -131,11 +131,11 @@ module Barometer
131
131
  end
132
132
  offset
133
133
  end
134
-
134
+
135
135
  def self._load_zone_codes
136
136
  $:.unshift(File.dirname(__FILE__))
137
137
  @@zone_codes ||= YAML.load_file(@@zone_codes_file)
138
138
  end
139
-
139
+
140
140
  end
141
- end
141
+ end
@@ -10,4 +10,4 @@ require 'formats/weather_id'
10
10
  require 'formats/coordinates'
11
11
  require 'formats/icao'
12
12
  require 'formats/geocode'
13
- require 'formats/woe_id'
13
+ require 'formats/woe_id'
@@ -8,20 +8,20 @@ module Barometer
8
8
  # :coordinates and how to convert to :coordinates.
9
9
  #
10
10
  class Query::Format::Coordinates < Query::Format
11
-
11
+
12
12
  def self.format; :coordinates; end
13
13
  def self.regex; /^[-]?[0-9\.]+[,]{1}\s?[-]?[0-9\.]+$/; end
14
14
  def self.convertable_formats
15
15
  [:short_zipcode, :zipcode, :postalcode, :weather_id, :coordinates, :icao, :geocode, :woe_id]
16
16
  end
17
-
17
+
18
18
  # convert to this format, X -> :coordinates
19
19
  #
20
20
  def self.to(original_query)
21
21
  raise ArgumentError unless is_a_query?(original_query)
22
22
  return nil unless converts?(original_query)
23
23
  converted_query = Barometer::Query.new
24
-
24
+
25
25
  # pre-convert
26
26
  #
27
27
  pre_query = nil
@@ -33,7 +33,7 @@ module Barometer
33
33
  elsif original_query.format == :woe_id
34
34
  pre_query = Query::Format::WoeID.reverse(original_query)
35
35
  end
36
-
36
+
37
37
  # convert & adjust
38
38
  #
39
39
  converted_query = Query::Format::Geocode.geocode(pre_query || original_query)
@@ -42,16 +42,16 @@ module Barometer
42
42
 
43
43
  converted_query
44
44
  end
45
-
45
+
46
46
  def self.parse_latitude(query)
47
47
  coordinates = query.to_s.split(',')
48
48
  coordinates ? coordinates[0] : nil
49
49
  end
50
-
50
+
51
51
  def self.parse_longitude(query)
52
52
  coordinates = query.to_s.split(',')
53
53
  coordinates ? coordinates[1] : nil
54
54
  end
55
55
 
56
56
  end
57
- end
57
+ end
@@ -18,14 +18,14 @@ module Barometer
18
18
  #
19
19
  def self.regex; raise NotImplementedError; end
20
20
  def self.format; raise NotImplementedError; end
21
-
21
+
22
22
  # defaults
23
23
  #
24
24
  def self.to(query=nil,country=nil); nil; end
25
25
  def self.country_code(query=nil); nil; end
26
26
  def self.convertable_formats; []; end
27
27
  def self.convert_query(text); text; end
28
-
28
+
29
29
  # is the query of this format?
30
30
  #
31
31
  def self.is?(query=nil)
@@ -46,9 +46,9 @@ module Barometer
46
46
  return false unless object
47
47
  object.is_a?(Barometer::Query)
48
48
  end
49
-
49
+
50
50
  private
51
-
51
+
52
52
  # fix the country code
53
53
  #
54
54
  # weather.com uses non-standard two letter country codes that
@@ -59,6 +59,6 @@ module Barometer
59
59
  @@fixes ||= YAML.load_file(@@fixes_file)
60
60
  @@fixes[country_code.upcase.to_s] || country_code
61
61
  end
62
-
62
+
63
63
  end
64
- end
64
+ end
@@ -23,10 +23,10 @@ module Barometer
23
23
  unless converts?(original_query)
24
24
  return (original_query.format == format ? original_query.dup : nil)
25
25
  end
26
-
26
+
27
27
  unless converted_query = original_query.get_conversion(format)
28
28
  converted_query = Barometer::Query.new
29
-
29
+
30
30
  converted_query = case original_query.format
31
31
  when :weather_id
32
32
  Query::Format::WeatherID.reverse(original_query)
@@ -35,7 +35,7 @@ module Barometer
35
35
  else
36
36
  geocode(original_query)
37
37
  end
38
-
38
+
39
39
  original_query.post_conversion(converted_query) if converted_query
40
40
  end
41
41
  converted_query
@@ -45,7 +45,7 @@ module Barometer
45
45
  #
46
46
  def self.geocode(original_query)
47
47
  raise ArgumentError unless is_a_query?(original_query)
48
-
48
+
49
49
  converted_query = Barometer::Query.new
50
50
  converted_query.geo = Barometer::WebService::Geocode.fetch(original_query)
51
51
  if converted_query.geo
@@ -57,4 +57,4 @@ module Barometer
57
57
  end
58
58
 
59
59
  end
60
- end
60
+ end
@@ -2,26 +2,26 @@ module Barometer
2
2
  #
3
3
  # Format: ICAO (International Civil Aviation Organization)
4
4
  #
5
- # eg. KLAX (Los Angeles Airport)
5
+ # eg. KLAX (Los Angeles Airport)
6
6
  #
7
7
  # This class is used to determine if a query is a
8
8
  # :icao and what the country_code is.
9
9
  #
10
10
  class Query::Format::Icao < Query::Format
11
-
11
+
12
12
  @@codes_file = File.expand_path(
13
13
  File.join(File.dirname(__FILE__), '..', 'translations', 'icao_country_codes.yml'))
14
14
  @@codes = nil
15
15
 
16
16
  def self.format; :icao; end
17
-
17
+
18
18
  # call any 3-4 letter query, :icao ... obviously this will have a lot
19
19
  # of false positives. So far this isn't an issue as all weather services
20
20
  # that take :icao (which is just one, :wunderground) also take what
21
21
  # this would have been if it was not called :icao.
22
22
  #
23
23
  def self.regex; /^[A-Za-z]{3,4}$/; end
24
-
24
+
25
25
  # in some cases the first letter can designate the country
26
26
  #
27
27
  def self.country_code(query=nil)
@@ -32,6 +32,6 @@ module Barometer
32
32
  @@codes['one_letter'][query[0..0].upcase.to_s] ||
33
33
  @@codes['two_letter'][query[0..1].upcase.to_s] || nil
34
34
  end
35
-
35
+
36
36
  end
37
- end
37
+ end
@@ -8,7 +8,7 @@ module Barometer
8
8
  # :postalcode and what the country_code is.
9
9
  #
10
10
  class Query::Format::Postalcode < Query::Format
11
-
11
+
12
12
  def self.format; :postalcode; end
13
13
  def self.country_code(query=nil); "CA"; end
14
14
  def self.regex
@@ -17,6 +17,6 @@ module Barometer
17
17
  # [ ]?[0-9]{1}[ABCEGHJ-NPRSTV-Z]{1}[0-9]{1}$
18
18
  /^[A-Z]{1}[\d]{1}[A-Z]{1}[ ]?[\d]{1}[A-Z]{1}[\d]{1}$/
19
19
  end
20
-
20
+
21
21
  end
22
- end
22
+ end
@@ -8,10 +8,10 @@ module Barometer
8
8
  # :short_zipcode and what the country_code is.
9
9
  #
10
10
  class Query::Format::ShortZipcode < Query::Format
11
-
11
+
12
12
  def self.format; :short_zipcode; end
13
13
  def self.country_code(query=nil); "US"; end
14
14
  def self.regex; /(^[0-9]{5}$)/; end
15
15
 
16
16
  end
17
- end
17
+ end
@@ -9,19 +9,19 @@ module Barometer
9
9
  # and what the country_code is.
10
10
  #
11
11
  class Query::Format::WeatherID < Query::Format
12
-
12
+
13
13
  def self.format; :weather_id; end
14
14
  def self.regex; /(^[A-Za-z]{4}[0-9]{4}$)/; end
15
15
  def self.convertable_formats
16
16
  [:short_zipcode, :zipcode, :coordinates, :icao, :geocode]
17
17
  end
18
-
18
+
19
19
  # the first two letters of the :weather_id is the country_code
20
20
  #
21
21
  def self.country_code(query=nil)
22
22
  (query && query.size >= 2) ? _fix_country(query[0..1]) : nil
23
23
  end
24
-
24
+
25
25
  # convert to this format, X -> :weather_id
26
26
  #
27
27
  def self.to(original_query)
@@ -37,7 +37,7 @@ module Barometer
37
37
  converted_query.country_code = country_code(converted_query.q)
38
38
  converted_query
39
39
  end
40
-
40
+
41
41
  # reverse lookup, :weather_id -> (:geocode || :coordinates)
42
42
  #
43
43
  def self.reverse(original_query)
@@ -48,9 +48,9 @@ module Barometer
48
48
  converted_query.format = Query::Format::Geocode.format
49
49
  converted_query
50
50
  end
51
-
51
+
52
52
  private
53
-
53
+
54
54
  # :geocode -> :weather_id
55
55
  # search weather.com for the given query
56
56
  #
@@ -60,7 +60,7 @@ module Barometer
60
60
  response = WebService::WeatherID.fetch(query)
61
61
  _parse_weather_id(response)
62
62
  end
63
-
63
+
64
64
  # :weather_id -> :geocode
65
65
  # query yahoo with :weather_id and parse geo_data
66
66
  #
@@ -70,7 +70,7 @@ module Barometer
70
70
  response = WebService::WeatherID.reverse(query)
71
71
  _parse_geocode(response)
72
72
  end
73
-
73
+
74
74
  # match the first :weather_id (from search results)
75
75
  #
76
76
  def self._parse_weather_id(text)
@@ -78,7 +78,7 @@ module Barometer
78
78
  match = text.match(/loc id=[\\]?['|""]([0-9a-zA-Z]*)[\\]?['|""]/)
79
79
  match ? match[1] : nil
80
80
  end
81
-
81
+
82
82
  # parse the geo_data
83
83
  #
84
84
  def self._parse_geocode(text)
@@ -89,4 +89,4 @@ module Barometer
89
89
  end
90
90
 
91
91
  end
92
- end
92
+ end