ullr 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/README.md +2 -2
- data/lib/ullr/forecast.rb +52 -0
- data/lib/ullr/noaa.rb +205 -0
- data/version.txt +1 -1
- metadata +8 -6
data/History.txt
CHANGED
data/README.md
CHANGED
@@ -12,8 +12,8 @@ Features
|
|
12
12
|
Examples
|
13
13
|
--------
|
14
14
|
|
15
|
-
iheartsnow = Ullr::Forecast.new(:lat => 43.98, :lon => -121.68)
|
16
|
-
iheartsnow.get_nooa_forecast
|
15
|
+
* iheartsnow = Ullr::Forecast.new(:lat => 43.98, :lon => -121.68)
|
16
|
+
* iheartsnow.get_nooa_forecast
|
17
17
|
|
18
18
|
Run Tests
|
19
19
|
---------
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Ullr
|
2
|
+
class Forecast
|
3
|
+
require 'open-uri'
|
4
|
+
require 'ostruct'
|
5
|
+
attr_accessor :lat, :lon, :forecast_string, :noaa_endpoint, :data, :socket_error
|
6
|
+
NOAA_ENDPOINT = "http://forecast.weather.gov/MapClick.php?lat={{lat}}&lon={{lon}}&FcstType=dwml"
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
[:lat,:lon].each do |o|
|
10
|
+
raise(ArgumentError, "#{o.to_s} is required!") if !options[o] || !options[o].instance_of?(Float)
|
11
|
+
end
|
12
|
+
@lat = options[:lat]
|
13
|
+
@lon = options[:lon]
|
14
|
+
@noaa_endpoint = NOAA_ENDPOINT.gsub("{{lat}}",@lat.to_s).gsub("{{lon}}",@lon.to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_noaa_forecast
|
18
|
+
@socket_error = false
|
19
|
+
@data = []
|
20
|
+
begin
|
21
|
+
resp = open(@noaa_endpoint)
|
22
|
+
@forecast_string = resp.read
|
23
|
+
rescue SocketError
|
24
|
+
@socket_error = true
|
25
|
+
end
|
26
|
+
if !@socket_error
|
27
|
+
data = Ullr::NOAA::Data.parse(@forecast_string)
|
28
|
+
forecast = data.find{|o| o.type == 'forecast'}
|
29
|
+
if forecast
|
30
|
+
time_layout = forecast.time_layouts.find{|t| t.layout_key =~ /k-p12h/ }
|
31
|
+
time_layout.start_valid_times.each_with_index do |time,i|
|
32
|
+
params = forecast.parameters
|
33
|
+
word = params.worded_forecast.texts[i]
|
34
|
+
point = OpenStruct.new
|
35
|
+
point.start_time = time.period_start
|
36
|
+
point.name = time.period_name
|
37
|
+
point.pop = params.pops.values[i].value
|
38
|
+
point.text = word.value
|
39
|
+
point.snow = word.has_snow?
|
40
|
+
point.high_temperature = word.high_temperature
|
41
|
+
point.low_temperature = word.low_temperature
|
42
|
+
point.wind_direction = word.wind_direction
|
43
|
+
point.wind_speeds = word.wind_speeds
|
44
|
+
point.snow_estimate = word.snow_estimate
|
45
|
+
@data << point
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
return @data
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/ullr/noaa.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'happymapper'
|
2
|
+
module Ullr
|
3
|
+
module NOAA
|
4
|
+
class StartValidTime
|
5
|
+
include HappyMapper
|
6
|
+
tag 'start-valid-time'
|
7
|
+
content :period_start
|
8
|
+
attribute :'period-name', String
|
9
|
+
set_time = lambda{|ob| ob.period_start = DateTime.parse(ob.period_start) }
|
10
|
+
after_parse(&set_time)
|
11
|
+
end
|
12
|
+
|
13
|
+
class TimeLayout
|
14
|
+
include HappyMapper
|
15
|
+
tag 'time-layout'
|
16
|
+
attribute :'time-coordinate', String
|
17
|
+
attribute :summarization, String
|
18
|
+
element :'layout-key', String
|
19
|
+
has_many :start_valid_times, StartValidTime
|
20
|
+
end
|
21
|
+
|
22
|
+
class Value
|
23
|
+
include HappyMapper
|
24
|
+
content :value
|
25
|
+
end
|
26
|
+
|
27
|
+
class Temperature
|
28
|
+
include HappyMapper
|
29
|
+
tag 'temperature'
|
30
|
+
element :name, String
|
31
|
+
attribute :type, String
|
32
|
+
attribute :units, String
|
33
|
+
attribute :'time-layout', String
|
34
|
+
has_many :values, Value
|
35
|
+
end
|
36
|
+
|
37
|
+
class POP
|
38
|
+
include HappyMapper
|
39
|
+
tag 'probability-of-precipitation'
|
40
|
+
element :name, String
|
41
|
+
attribute :type, String
|
42
|
+
attribute :units, String
|
43
|
+
attribute :'time-layout', String
|
44
|
+
has_many :values, Value
|
45
|
+
end
|
46
|
+
|
47
|
+
class WeatherCondition
|
48
|
+
include HappyMapper
|
49
|
+
tag 'weather-conditions'
|
50
|
+
attribute :'weather-summary', String
|
51
|
+
end
|
52
|
+
|
53
|
+
class Weather
|
54
|
+
include HappyMapper
|
55
|
+
tag 'weather'
|
56
|
+
attribute :'time-layout', String
|
57
|
+
element :name, String
|
58
|
+
has_many :weather_conditions, WeatherCondition
|
59
|
+
end
|
60
|
+
|
61
|
+
class IconLink
|
62
|
+
include HappyMapper
|
63
|
+
tag 'icon-link'
|
64
|
+
content :url
|
65
|
+
end
|
66
|
+
|
67
|
+
class ConditionsIcon
|
68
|
+
include HappyMapper
|
69
|
+
tag 'conditions-icon'
|
70
|
+
attribute :'time-layout', String
|
71
|
+
element :name, String
|
72
|
+
has_many :icon_links, IconLink
|
73
|
+
end
|
74
|
+
|
75
|
+
class Text
|
76
|
+
include HappyMapper
|
77
|
+
tag 'text'
|
78
|
+
content :value
|
79
|
+
|
80
|
+
def has_snow?
|
81
|
+
if self.value =~ /snow/i
|
82
|
+
return true
|
83
|
+
else
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def snow_estimate
|
89
|
+
rng = ['0','0']
|
90
|
+
range = self.value.scan(/New snow accumulation of (0|[1-9]\d*) to (0|[1-9]\d*)/)
|
91
|
+
one = self.value.scan(/around an inch possible/)
|
92
|
+
if !one.empty?
|
93
|
+
rng = ['0','1']
|
94
|
+
elsif !range.empty?
|
95
|
+
rng = range.first
|
96
|
+
elsif self.has_snow?
|
97
|
+
rng = ['0','1']
|
98
|
+
end
|
99
|
+
return rng
|
100
|
+
end
|
101
|
+
|
102
|
+
def wind_direction
|
103
|
+
direction = self.value.scan(/ (\w*) wind [around|between]/i)
|
104
|
+
if !direction.empty?
|
105
|
+
direction = direction.first[0].downcase
|
106
|
+
else
|
107
|
+
direction = ''
|
108
|
+
end
|
109
|
+
return direction
|
110
|
+
end
|
111
|
+
|
112
|
+
def wind_speeds
|
113
|
+
rng = ['','']
|
114
|
+
range = self.value.scan(/ wind between (0|[1-9]\d*) and (0|[1-9]\d*)/i)
|
115
|
+
one = self.value.scan(/ wind around (0|[1-9]\d*)/i)
|
116
|
+
if !one.empty?
|
117
|
+
speed = one.first[0]
|
118
|
+
rng = [speed,speed]
|
119
|
+
elsif !range.empty?
|
120
|
+
rng = range.first
|
121
|
+
end
|
122
|
+
return rng
|
123
|
+
end
|
124
|
+
|
125
|
+
def high_temperature
|
126
|
+
high = ''
|
127
|
+
high_temp = self.value.scan(/high near (0|[1-9]\d*)/)
|
128
|
+
if !high_temp.empty?
|
129
|
+
high = high_temp.first[0]
|
130
|
+
end
|
131
|
+
return high
|
132
|
+
end
|
133
|
+
|
134
|
+
def low_temperature
|
135
|
+
low = ''
|
136
|
+
low_temp = self.value.scan(/low around (0|[1-9]\d*)/)
|
137
|
+
if !low_temp.empty?
|
138
|
+
low = low_temp.first[0]
|
139
|
+
end
|
140
|
+
return low
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class WordedForecast
|
145
|
+
include HappyMapper
|
146
|
+
tag 'wordedForecast'
|
147
|
+
attribute :'time-layout', String
|
148
|
+
attribute :dataSource, String
|
149
|
+
attribute :wordGenerator, String
|
150
|
+
element :name, String
|
151
|
+
has_many :texts, Text
|
152
|
+
end
|
153
|
+
|
154
|
+
class Parameters
|
155
|
+
include HappyMapper
|
156
|
+
tag 'parameters'
|
157
|
+
has_many :temperatures, Temperature
|
158
|
+
has_one :pops, POP
|
159
|
+
has_one :weather, Weather
|
160
|
+
has_one :conditions_icon, ConditionsIcon
|
161
|
+
has_one :worded_forecast, WordedForecast
|
162
|
+
end
|
163
|
+
|
164
|
+
class Point
|
165
|
+
include HappyMapper
|
166
|
+
tag 'point'
|
167
|
+
attribute :latitude, String
|
168
|
+
attribute :longitude, String
|
169
|
+
end
|
170
|
+
|
171
|
+
class City
|
172
|
+
include HappyMapper
|
173
|
+
tag 'city'
|
174
|
+
content :name
|
175
|
+
attribute :state, String
|
176
|
+
end
|
177
|
+
|
178
|
+
class Height
|
179
|
+
include HappyMapper
|
180
|
+
tag 'height'
|
181
|
+
attribute :datum, String
|
182
|
+
content :elevation
|
183
|
+
end
|
184
|
+
|
185
|
+
class Location
|
186
|
+
include HappyMapper
|
187
|
+
tag 'location'
|
188
|
+
element :'location-key', String
|
189
|
+
element :description, String
|
190
|
+
has_one :point, Point
|
191
|
+
has_one :city, City
|
192
|
+
has_one :height, Height
|
193
|
+
end
|
194
|
+
|
195
|
+
class Data
|
196
|
+
include HappyMapper
|
197
|
+
tag 'data'
|
198
|
+
has_one :parameters, Parameters
|
199
|
+
has_one :location, Location
|
200
|
+
has_many :time_layouts, TimeLayout
|
201
|
+
attribute :type, String
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
data/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ullr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-12-
|
12
|
+
date: 2011-12-21 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: happymapper
|
16
|
-
requirement: &
|
16
|
+
requirement: &70189069609900 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.4.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70189069609900
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bones
|
27
|
-
requirement: &
|
27
|
+
requirement: &70189069635680 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 3.7.3
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70189069635680
|
36
36
|
description: ullr is a little gem that consumes NOAA weather xml for a given lat/long,
|
37
37
|
and returns an array of data with 12 hour forecasts along with some sugar to let
|
38
38
|
you know if any sugar will be falling from the sky.
|
@@ -50,6 +50,8 @@ files:
|
|
50
50
|
- Rakefile
|
51
51
|
- bin/ullr
|
52
52
|
- lib/ullr.rb
|
53
|
+
- lib/ullr/noaa.rb
|
54
|
+
- lib/ullr/forecast.rb
|
53
55
|
- spec/spec_helper.rb
|
54
56
|
- spec/ullr_spec.rb
|
55
57
|
- version.txt
|