buoy_data 0.2.0 → 1.0.0.beta.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/buoy_data.gemspec +21 -7
- data/lib/buoy_data/buoy_list.rb +66 -0
- data/lib/buoy_data/{buoy.rb → buoy_reading.rb} +1 -1
- data/lib/buoy_data/noaa_buoy_forecast.rb +149 -0
- data/lib/buoy_data/noaa_buoy_list.rb +49 -0
- data/lib/buoy_data/{noaa_buoy.rb → noaa_buoy_observation.rb} +40 -70
- data/lib/buoy_data/noaa_buoy_reading.rb +69 -0
- data/lib/buoy_data.rb +6 -2
- data/spec/noaa_buoy_forecast_spec.rb +28 -0
- data/spec/noaa_buoy_list_spec.rb +19 -0
- data/spec/noaa_buoy_observation_spec.rb +57 -0
- metadata +49 -11
- data/spec/noaa_buoy_spec.rb +0 -28
data/Rakefile
CHANGED
@@ -12,6 +12,8 @@ begin
|
|
12
12
|
gem.authors = ["Adam Weller"]
|
13
13
|
gem.add_development_dependency 'rspec'
|
14
14
|
gem.add_dependency 'httparty'
|
15
|
+
gem.add_dependency 'json'
|
16
|
+
gem.add_dependency 'nokogiri'
|
15
17
|
gem.files.include 'lib/buoy_data/*.rb'
|
16
18
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
19
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0.beta.0
|
data/buoy_data.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{buoy_data}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0.beta.0"
|
9
9
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Adam Weller"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-03-20}
|
13
13
|
s.description = %q{The goal of this gem is to provide marine buoy data from a variety of sources}
|
14
14
|
s.email = %q{minch@trazzler.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,9 +25,15 @@ Gem::Specification.new do |s|
|
|
25
25
|
"VERSION",
|
26
26
|
"buoy_data.gemspec",
|
27
27
|
"lib/buoy_data.rb",
|
28
|
-
"lib/buoy_data/
|
29
|
-
"lib/buoy_data/
|
30
|
-
"
|
28
|
+
"lib/buoy_data/buoy_list.rb",
|
29
|
+
"lib/buoy_data/buoy_reading.rb",
|
30
|
+
"lib/buoy_data/noaa_buoy_forecast.rb",
|
31
|
+
"lib/buoy_data/noaa_buoy_list.rb",
|
32
|
+
"lib/buoy_data/noaa_buoy_observation.rb",
|
33
|
+
"lib/buoy_data/noaa_buoy_reading.rb",
|
34
|
+
"spec/noaa_buoy_forecast_spec.rb",
|
35
|
+
"spec/noaa_buoy_list_spec.rb",
|
36
|
+
"spec/noaa_buoy_observation_spec.rb",
|
31
37
|
"spec/spec_helper.rb"
|
32
38
|
]
|
33
39
|
s.homepage = %q{http://github.com/minch/buoy_data}
|
@@ -36,7 +42,9 @@ Gem::Specification.new do |s|
|
|
36
42
|
s.rubygems_version = %q{1.3.7}
|
37
43
|
s.summary = %q{Fetch marine buoy data from various sources}
|
38
44
|
s.test_files = [
|
39
|
-
"spec/
|
45
|
+
"spec/noaa_buoy_forecast_spec.rb",
|
46
|
+
"spec/noaa_buoy_list_spec.rb",
|
47
|
+
"spec/noaa_buoy_observation_spec.rb",
|
40
48
|
"spec/spec_helper.rb"
|
41
49
|
]
|
42
50
|
|
@@ -47,13 +55,19 @@ Gem::Specification.new do |s|
|
|
47
55
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
56
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
49
57
|
s.add_runtime_dependency(%q<httparty>, [">= 0"])
|
58
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
59
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
50
60
|
else
|
51
61
|
s.add_dependency(%q<rspec>, [">= 0"])
|
52
62
|
s.add_dependency(%q<httparty>, [">= 0"])
|
63
|
+
s.add_dependency(%q<json>, [">= 0"])
|
64
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
53
65
|
end
|
54
66
|
else
|
55
67
|
s.add_dependency(%q<rspec>, [">= 0"])
|
56
68
|
s.add_dependency(%q<httparty>, [">= 0"])
|
69
|
+
s.add_dependency(%q<json>, [">= 0"])
|
70
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
57
71
|
end
|
58
72
|
end
|
59
73
|
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module BuoyData
|
2
|
+
require 'open-uri'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
class BuoyList
|
6
|
+
def get
|
7
|
+
stats = {
|
8
|
+
:stations => [],
|
9
|
+
:errors => []
|
10
|
+
}
|
11
|
+
@doc = doc
|
12
|
+
@station_list = stations doc
|
13
|
+
|
14
|
+
@station_list.each do |s|
|
15
|
+
begin
|
16
|
+
h = scrape_station s
|
17
|
+
stats[:stations].push h
|
18
|
+
rescue => e
|
19
|
+
stats[:errors].push({ :url => s, :error => e })
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
stats
|
24
|
+
end
|
25
|
+
|
26
|
+
def url
|
27
|
+
end
|
28
|
+
|
29
|
+
def base_url
|
30
|
+
end
|
31
|
+
|
32
|
+
def doc
|
33
|
+
doc = Nokogiri::HTML(open(url))
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def stations(doc)
|
38
|
+
end
|
39
|
+
|
40
|
+
def scrape_station(url)
|
41
|
+
end
|
42
|
+
|
43
|
+
def lat_lng_from(text)
|
44
|
+
text = text.sub(/ \(.*$/, '')
|
45
|
+
matches = /([0-9\.]+ ?[NESW]) ([0-9\.]+ ?[NESW])/.match(text)
|
46
|
+
|
47
|
+
matches && matches.size == 3 ? [ $1, $2 ] : []
|
48
|
+
end
|
49
|
+
|
50
|
+
def normal_lat(lat)
|
51
|
+
lat, dir = lat.split(/ /)
|
52
|
+
lat = lat.to_f
|
53
|
+
lat = -lat if dir == 'S'
|
54
|
+
|
55
|
+
lat
|
56
|
+
end
|
57
|
+
|
58
|
+
def normal_lng(lng)
|
59
|
+
lng, dir = lng.split(/ /)
|
60
|
+
lng = lng.to_f
|
61
|
+
lng = -lng if dir == 'W'
|
62
|
+
|
63
|
+
lng
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module BuoyData
|
2
|
+
class NoaaBuoyForecast < NoaaBuoyReading
|
3
|
+
require 'json/add/core'
|
4
|
+
|
5
|
+
def get(raw = true)
|
6
|
+
response = super raw
|
7
|
+
return unless response
|
8
|
+
@response = response
|
9
|
+
|
10
|
+
@parsed_response = parse_response @response
|
11
|
+
end
|
12
|
+
|
13
|
+
# This pattern differs from the previous design but seems better
|
14
|
+
def to_json
|
15
|
+
response = @parsed_response
|
16
|
+
response = response.map{|row| bull_row_to_hash row}
|
17
|
+
response.to_json
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def bull_row_to_hash(row)
|
23
|
+
hash = {
|
24
|
+
:time => { :day => row[0][0], :hour => row[0][1] },
|
25
|
+
:total => { :hst => row[1][0], :n => row[1][1], :x => row[1][2] }
|
26
|
+
}
|
27
|
+
5.times do |index|
|
28
|
+
hash.store("separate_wave_#{index}".to_sym, separate_wave_hash(row[2..row.size-1]))
|
29
|
+
end
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
|
33
|
+
def separate_wave_hash(array)
|
34
|
+
h = {
|
35
|
+
:wind => array[0],
|
36
|
+
:hs => array[1],
|
37
|
+
:tp => array[2],
|
38
|
+
:dir => array[3]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_response(response)
|
43
|
+
# Get all readings
|
44
|
+
response = response_to_array response
|
45
|
+
|
46
|
+
# Remove header and footer
|
47
|
+
response = remove_header_from response
|
48
|
+
response = remove_footer_from response
|
49
|
+
|
50
|
+
# Now really go through this gnarly bull format and make some sense of it
|
51
|
+
response = parse_bull_response response
|
52
|
+
|
53
|
+
response
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_bull_response(response)
|
57
|
+
parsed_response = []
|
58
|
+
|
59
|
+
#
|
60
|
+
# Split on pipes so we can get the swell breakdown
|
61
|
+
#
|
62
|
+
response = response.map{|row| row.split(/\|/)}
|
63
|
+
|
64
|
+
# The first column is always empty
|
65
|
+
response = response.map{|row| row[1..row.size-1]}
|
66
|
+
|
67
|
+
#
|
68
|
+
# Now we have eight columns
|
69
|
+
#
|
70
|
+
# 1: day and hour
|
71
|
+
# 2: Total Significant wave height and exclusions (Hst, n and x)
|
72
|
+
# 3-7: Up to 6 swell breakdowns (* Hs, Tp, dir)
|
73
|
+
#
|
74
|
+
# Where:
|
75
|
+
#
|
76
|
+
# Hst : Total significant wave height.
|
77
|
+
# n : Number of fields with Hs > 0.05 in 2-D spectrum.
|
78
|
+
# x : Number of fields with Hs > 0.15 not in table.
|
79
|
+
# Hs : Significant wave height of separate wave field.
|
80
|
+
# Tp : Peak period of separate wave field.
|
81
|
+
# dir : Mean direction of separate wave field.
|
82
|
+
# * : Wave generation due to local wind probable.
|
83
|
+
#
|
84
|
+
|
85
|
+
days_and_hours = response.map{|row| row.first.strip.split(/\s+/)}
|
86
|
+
|
87
|
+
#
|
88
|
+
# totals
|
89
|
+
#
|
90
|
+
totals = response.map do |row|
|
91
|
+
row = row[1].strip.split(/\s+/)
|
92
|
+
row = row.size == 3 ? row : row << ""
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# up to 6 swells
|
97
|
+
#
|
98
|
+
separate_waves = response.map{|row| row[2..7].map{|col| parse_separate_wave(col)}}
|
99
|
+
|
100
|
+
# build the parsed_response
|
101
|
+
num = response.size-1
|
102
|
+
num.times do |index|
|
103
|
+
row = []
|
104
|
+
|
105
|
+
row.push days_and_hours[index]
|
106
|
+
row.push totals[index]
|
107
|
+
separate_waves[index].each do |sw|
|
108
|
+
row.push sw
|
109
|
+
end
|
110
|
+
|
111
|
+
parsed_response.push row
|
112
|
+
end
|
113
|
+
|
114
|
+
parsed_response
|
115
|
+
end
|
116
|
+
|
117
|
+
# Example: "* 1.3 5.3 298"
|
118
|
+
def parse_separate_wave(separate_wave)
|
119
|
+
# There's probably a slicker way but...
|
120
|
+
separate_wave = separate_wave.split(/\s+/)
|
121
|
+
|
122
|
+
# The first column, the wind probable '*', may or may not be present
|
123
|
+
# In either cases we have an empty string as the first field
|
124
|
+
separate_wave.size == 5 ? separate_wave.shift : separate_wave
|
125
|
+
|
126
|
+
separate_wave
|
127
|
+
end
|
128
|
+
|
129
|
+
def base_url(buoy_id = @buoy_id)
|
130
|
+
@buoy_id ||= buoy_id
|
131
|
+
|
132
|
+
# NOTE: The bull files will probably change per ocean/geo:
|
133
|
+
# E.g., there are two model runs for the northern atlantic:
|
134
|
+
#"http://polar.ncep.noaa.gov/waves/latest_run/nah.#{buoy_id}.bull"
|
135
|
+
|
136
|
+
"http://polar.ncep.noaa.gov/waves/latest_run/wna.#{buoy_id}.bull"
|
137
|
+
end
|
138
|
+
|
139
|
+
# The header is the first 7 lines
|
140
|
+
def remove_header_from(response)
|
141
|
+
response[7..response.size-1]
|
142
|
+
end
|
143
|
+
|
144
|
+
# The footer is the last 8 lines
|
145
|
+
def remove_footer_from(response)
|
146
|
+
response[0..response.size-11]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module BuoyData
|
2
|
+
class NoaaBuoyList < BuoyList
|
3
|
+
def url
|
4
|
+
"#{base_url}/to_station.shtml"
|
5
|
+
end
|
6
|
+
|
7
|
+
def base_url
|
8
|
+
'http://www.ndbc.noaa.gov'
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def stations(doc)
|
13
|
+
text = "National Data Buoy Center Stations"
|
14
|
+
xpath = "//h4[text()='#{text}']/following-sibling::pre/a"
|
15
|
+
|
16
|
+
doc.xpath(xpath).map{|element| element['href']}
|
17
|
+
end
|
18
|
+
|
19
|
+
def scrape_station(url)
|
20
|
+
url = [base_url, url].join('/')
|
21
|
+
doc = Nokogiri::HTML(open(url))
|
22
|
+
h = {}
|
23
|
+
xpath = "//h1"
|
24
|
+
|
25
|
+
# Title, Station Id and Description
|
26
|
+
title = doc.xpath(xpath).text
|
27
|
+
h[:url] = url
|
28
|
+
h[:title] = title
|
29
|
+
station_id, description = title.split(/ - /)
|
30
|
+
station_id = station_id.sub(/station ?/i, '')
|
31
|
+
h[:station_id] = station_id
|
32
|
+
h[:description] = description
|
33
|
+
|
34
|
+
# Lat and Lng
|
35
|
+
xpath += "/following-sibling::table/tr/td/p/b"
|
36
|
+
elements = doc.xpath(xpath)
|
37
|
+
elements = elements.map(&:text)
|
38
|
+
element = elements.find{|e| /\d{2,3}\.\d{2,3}/.match(e)}
|
39
|
+
latlng = lat_lng_from element
|
40
|
+
|
41
|
+
unless latlng.empty?
|
42
|
+
h[:lat] = normal_lat latlng.first
|
43
|
+
h[:lng] = normal_lng latlng.last
|
44
|
+
end
|
45
|
+
|
46
|
+
h
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,34 +1,53 @@
|
|
1
1
|
module BuoyData
|
2
|
-
class
|
3
|
-
|
2
|
+
class NoaaBuoyObservation < NoaaBuoyReading
|
3
|
+
require 'json/add/core'
|
4
4
|
|
5
|
-
|
5
|
+
def get_all(format = :plain)
|
6
|
+
response = get(true)
|
7
|
+
return unless response
|
8
|
+
response = response_to_array response
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
10
|
+
case format
|
11
|
+
when :json
|
12
|
+
json_response = []
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
fields = fields_from_response response
|
15
|
+
# Remvoe the field rows
|
16
|
+
response = response[2..response.size-1]
|
17
|
+
|
18
|
+
response.each do |reading|
|
19
|
+
reading = reading.split
|
20
|
+
json = reading_to_hash(reading, fields).to_json
|
21
|
+
json_response.push json
|
22
|
+
end
|
17
23
|
|
18
|
-
|
19
|
-
|
20
|
-
return unless response and response.code == GET_SUCCESS
|
21
|
-
return response if raw
|
24
|
+
response = json_response
|
25
|
+
end
|
22
26
|
|
23
|
-
|
24
|
-
parse_response
|
27
|
+
response
|
25
28
|
end
|
26
29
|
|
27
|
-
def
|
28
|
-
|
30
|
+
def parse_response(response)
|
31
|
+
# Get all readings
|
32
|
+
response = response_to_array response
|
33
|
+
# The first line are the fields
|
34
|
+
fields = fields_from_response response
|
35
|
+
|
36
|
+
# The second line are different names of the fields
|
37
|
+
# The third line is the most recent reading
|
38
|
+
response = most_recent_from_response response
|
29
39
|
return unless response
|
30
40
|
|
31
|
-
|
41
|
+
# Set instance vars per field so we can use dot notation to reference each
|
42
|
+
hash = reading_to_hash(response, fields)
|
43
|
+
define_attributes(hash)
|
44
|
+
end
|
45
|
+
|
46
|
+
def define_attributes(hash)
|
47
|
+
hash.each_pair { |key, value|
|
48
|
+
metaclass.send :attr_accessor, key
|
49
|
+
send "#{key}=".to_sym, value
|
50
|
+
}
|
32
51
|
end
|
33
52
|
|
34
53
|
#
|
@@ -72,54 +91,5 @@ module BuoyData
|
|
72
91
|
|
73
92
|
"http://www.ndbc.noaa.gov/data/realtime2/#{buoy_id}.spec"
|
74
93
|
end
|
75
|
-
|
76
|
-
def self.source
|
77
|
-
:noaa
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.google_chart_base(buoy_id)
|
81
|
-
url = [ "http://chart.apis.google.com/chart?cht=lc" ]
|
82
|
-
url << "chtt=#{buoy_id}"
|
83
|
-
url << "chts=666666,12"
|
84
|
-
url << "chco=3366FF"
|
85
|
-
url << "chs=250x100"
|
86
|
-
url << "chds=0,10"
|
87
|
-
url << "chl=WVHT".gsub(/ /, '%20')
|
88
|
-
url.join('&')
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
|
-
def self.default_unit_system
|
93
|
-
:metric
|
94
|
-
end
|
95
|
-
|
96
|
-
def parse_response
|
97
|
-
# Get all readings
|
98
|
-
response = @response.parsed_response.split(/\n/)
|
99
|
-
|
100
|
-
# The first line are the fields
|
101
|
-
fields = response.first.sub(/^#/, '').split
|
102
|
-
|
103
|
-
# The second line are different names of the fields
|
104
|
-
|
105
|
-
# The third line is the most recent reading
|
106
|
-
response = response[2].split rescue nil
|
107
|
-
return unless response
|
108
|
-
|
109
|
-
# Set instance vars per field so we can use dot notation to reference each
|
110
|
-
hash = {}
|
111
|
-
fields.each_with_index do |field, index|
|
112
|
-
hash.store(field, response[index])
|
113
|
-
end
|
114
|
-
|
115
|
-
define_attributes(hash)
|
116
|
-
end
|
117
|
-
|
118
|
-
def define_attributes(hash)
|
119
|
-
hash.each_pair { |key, value|
|
120
|
-
metaclass.send :attr_accessor, key
|
121
|
-
send "#{key}=".to_sym, value
|
122
|
-
}
|
123
|
-
end
|
124
94
|
end
|
125
95
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module BuoyData
|
2
|
+
class NoaaBuoyReading < BuoyReading
|
3
|
+
format :plain
|
4
|
+
|
5
|
+
attr_accessor :buoy_id, :url, :response
|
6
|
+
|
7
|
+
def initialize(buoy_id, unit_system = self.class.default_unit_system)
|
8
|
+
@url = base_url(buoy_id)
|
9
|
+
@unit_system = unit_system
|
10
|
+
end
|
11
|
+
|
12
|
+
def metaclass
|
13
|
+
class << self
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def get(raw = false)
|
19
|
+
response = self.class.get(@url)
|
20
|
+
return unless response and response.code == GET_SUCCESS
|
21
|
+
return response if raw
|
22
|
+
|
23
|
+
@response = response
|
24
|
+
parse_response(response)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.source
|
28
|
+
:noaa
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.google_chart_base(buoy_id)
|
32
|
+
url = [ "http://chart.apis.google.com/chart?cht=lc" ]
|
33
|
+
url << "chtt=#{buoy_id}"
|
34
|
+
url << "chts=666666,12"
|
35
|
+
url << "chco=3366FF"
|
36
|
+
url << "chs=250x100"
|
37
|
+
url << "chds=0,10"
|
38
|
+
url << "chl=WVHT".gsub(/ /, '%20')
|
39
|
+
url.join('&')
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def self.default_unit_system
|
44
|
+
:metric
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def fields_from_response(response)
|
49
|
+
fields = response.first.sub(/^#/, '').split
|
50
|
+
end
|
51
|
+
|
52
|
+
def response_to_array(response)
|
53
|
+
response.parsed_response.split(/\n/)
|
54
|
+
end
|
55
|
+
|
56
|
+
def most_recent_from_response(response)
|
57
|
+
response[2].split rescue nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def reading_to_hash(reading, fields)
|
61
|
+
hash = {}
|
62
|
+
fields.each_with_index do |field, index|
|
63
|
+
hash.store(field, reading[index])
|
64
|
+
end
|
65
|
+
|
66
|
+
hash
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/buoy_data.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
1
|
require 'httparty'
|
2
|
-
require 'buoy_data/
|
3
|
-
require 'buoy_data/
|
2
|
+
require 'buoy_data/buoy_list'
|
3
|
+
require 'buoy_data/buoy_reading'
|
4
|
+
require 'buoy_data/noaa_buoy_reading'
|
5
|
+
require 'buoy_data/noaa_buoy_list'
|
6
|
+
require 'buoy_data/noaa_buoy_observation'
|
7
|
+
require 'buoy_data/noaa_buoy_forecast'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe BuoyData::NoaaBuoyForecast do
|
4
|
+
before(:each) do
|
5
|
+
#FakeWeb.allow_net_connect = false # TODO
|
6
|
+
end
|
7
|
+
|
8
|
+
let (:noaa_buoy_forecast) { BuoyData::NoaaBuoyForecast.new(41012) }
|
9
|
+
|
10
|
+
context 'get' do
|
11
|
+
before(:each) do
|
12
|
+
noaa_buoy_forecast.get
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should get buoy data' do
|
16
|
+
noaa_buoy_forecast.response.code.should == BuoyData::NoaaBuoyForecast::GET_SUCCESS
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should get buoy data as json' do
|
20
|
+
noaa_buoy_forecast.get
|
21
|
+
json = noaa_buoy_forecast.to_json
|
22
|
+
json.should be
|
23
|
+
# We really should get down and dirty here, thoroughly checking the fields
|
24
|
+
hash = JSON.parse(json).first
|
25
|
+
hash.should be_a Hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe BuoyData::NoaaBuoyList do
|
4
|
+
let (:buoy_list) { BuoyData::NoaaBuoyList.new }
|
5
|
+
|
6
|
+
context 'get' do
|
7
|
+
it "should get buoy list" do
|
8
|
+
buoy_list.should be
|
9
|
+
buoy_list.stub(:stations).and_return(stubbed_station_list)
|
10
|
+
stations = buoy_list.get
|
11
|
+
|
12
|
+
stations.should_not be_empty
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def stubbed_station_list
|
17
|
+
[ "station_page.php?station=41012", "station_page.php?station=sauf1" ]
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe BuoyData::NoaaBuoyObservation do
|
4
|
+
before(:each) do
|
5
|
+
#FakeWeb.allow_net_connect = false # TODO
|
6
|
+
end
|
7
|
+
|
8
|
+
let (:noaa_buoy_observation) { BuoyData::NoaaBuoyObservation.new(41012) }
|
9
|
+
|
10
|
+
context 'get' do
|
11
|
+
it 'should get buoy data' do
|
12
|
+
noaa_buoy_observation.get
|
13
|
+
noaa_buoy_observation.response.code.should == BuoyData::NoaaBuoyObservation::GET_SUCCESS
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should respond to noaa fields' do
|
17
|
+
noaa_buoy_observation.get
|
18
|
+
noaa_buoy_observation.should respond_to :WVHT
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should generate google chart url' do
|
22
|
+
noaa_buoy_observation.google_chart_url.should match(/chart.apis.google.com/)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should parse date fields' do
|
26
|
+
noaa_buoy_observation.get
|
27
|
+
noaa_buoy_observation.YY.should match(/^\d{4}$/)
|
28
|
+
noaa_buoy_observation.DD.should match(/^\d{2}$/)
|
29
|
+
noaa_buoy_observation.hh.should match(/^\d{2}$/)
|
30
|
+
noaa_buoy_observation.mm.should match(/^\d{2}$/)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'get_all' do
|
35
|
+
it 'should get all' do
|
36
|
+
response = noaa_buoy_observation.get_all
|
37
|
+
response.should be_a Array
|
38
|
+
response.size.should > 1
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should get all as :json' do
|
42
|
+
json = noaa_buoy_observation.get_all(:json)
|
43
|
+
hash = JSON.parse(json.first)
|
44
|
+
hash.should be_a(Hash)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should parse date fields' do
|
48
|
+
response = noaa_buoy_observation.get_all(:json)
|
49
|
+
noaa_buoy_observation = JSON.parse(response.first)
|
50
|
+
|
51
|
+
noaa_buoy_observation[:YY.to_s].should match(/^\d{4}$/)
|
52
|
+
noaa_buoy_observation[:DD.to_s].should match(/^\d{2}$/)
|
53
|
+
noaa_buoy_observation[:hh.to_s].should match(/^\d{2}$/)
|
54
|
+
noaa_buoy_observation[:mm.to_s].should match(/^\d{2}$/)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: buoy_data
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: true
|
5
5
|
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
6
8
|
- 0
|
7
|
-
-
|
9
|
+
- beta
|
8
10
|
- 0
|
9
|
-
version: 0.
|
11
|
+
version: 1.0.0.beta.0
|
10
12
|
platform: ruby
|
11
13
|
authors:
|
12
14
|
- Adam Weller
|
@@ -14,7 +16,7 @@ autorequire:
|
|
14
16
|
bindir: bin
|
15
17
|
cert_chain: []
|
16
18
|
|
17
|
-
date:
|
19
|
+
date: 2011-03-20 00:00:00 -04:00
|
18
20
|
default_executable:
|
19
21
|
dependencies:
|
20
22
|
- !ruby/object:Gem::Dependency
|
@@ -43,6 +45,32 @@ dependencies:
|
|
43
45
|
version: "0"
|
44
46
|
type: :runtime
|
45
47
|
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: json
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id003
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: nokogiri
|
63
|
+
prerelease: false
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
type: :runtime
|
73
|
+
version_requirements: *id004
|
46
74
|
description: The goal of this gem is to provide marine buoy data from a variety of sources
|
47
75
|
email: minch@trazzler.com
|
48
76
|
executables: []
|
@@ -61,9 +89,15 @@ files:
|
|
61
89
|
- VERSION
|
62
90
|
- buoy_data.gemspec
|
63
91
|
- lib/buoy_data.rb
|
64
|
-
- lib/buoy_data/
|
65
|
-
- lib/buoy_data/
|
66
|
-
-
|
92
|
+
- lib/buoy_data/buoy_list.rb
|
93
|
+
- lib/buoy_data/buoy_reading.rb
|
94
|
+
- lib/buoy_data/noaa_buoy_forecast.rb
|
95
|
+
- lib/buoy_data/noaa_buoy_list.rb
|
96
|
+
- lib/buoy_data/noaa_buoy_observation.rb
|
97
|
+
- lib/buoy_data/noaa_buoy_reading.rb
|
98
|
+
- spec/noaa_buoy_forecast_spec.rb
|
99
|
+
- spec/noaa_buoy_list_spec.rb
|
100
|
+
- spec/noaa_buoy_observation_spec.rb
|
67
101
|
- spec/spec_helper.rb
|
68
102
|
has_rdoc: true
|
69
103
|
homepage: http://github.com/minch/buoy_data
|
@@ -85,11 +119,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
120
|
none: false
|
87
121
|
requirements:
|
88
|
-
- - "
|
122
|
+
- - ">"
|
89
123
|
- !ruby/object:Gem::Version
|
90
124
|
segments:
|
91
|
-
-
|
92
|
-
|
125
|
+
- 1
|
126
|
+
- 3
|
127
|
+
- 1
|
128
|
+
version: 1.3.1
|
93
129
|
requirements: []
|
94
130
|
|
95
131
|
rubyforge_project:
|
@@ -98,5 +134,7 @@ signing_key:
|
|
98
134
|
specification_version: 3
|
99
135
|
summary: Fetch marine buoy data from various sources
|
100
136
|
test_files:
|
101
|
-
- spec/
|
137
|
+
- spec/noaa_buoy_forecast_spec.rb
|
138
|
+
- spec/noaa_buoy_list_spec.rb
|
139
|
+
- spec/noaa_buoy_observation_spec.rb
|
102
140
|
- spec/spec_helper.rb
|
data/spec/noaa_buoy_spec.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
-
|
3
|
-
describe BuoyData::NoaaBuoy do
|
4
|
-
before(:each) do
|
5
|
-
#FakeWeb.allow_net_connect = false # TODO
|
6
|
-
@noaa_buoy = BuoyData::NoaaBuoy.new(41114)
|
7
|
-
end
|
8
|
-
|
9
|
-
context 'get' do
|
10
|
-
it 'should get buoy data' do
|
11
|
-
@noaa_buoy.get
|
12
|
-
@noaa_buoy.response.code.should == BuoyData::NoaaBuoy::GET_SUCCESS
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'should respond to noaa fields' do
|
16
|
-
@noaa_buoy.get
|
17
|
-
@noaa_buoy.should respond_to :WVHT
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'should get all buoy data' do
|
21
|
-
@noaa_buoy.get_all.size.should >= 1
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'should get all buoy data' do
|
25
|
-
@noaa_buoy.google_chart_url.should match(/chart.apis.google.com/)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|