meteorology 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/features/meteorology.feature +12 -0
- data/features/step_definitions/meteorology_steps.rb +38 -0
- data/features/support/env.rb +23 -0
- data/fixtures/yr.no/locationforecast-1.6.xml +2548 -0
- data/lib/meteorology.rb +24 -0
- data/lib/meteorology/providers.rb +6 -0
- data/lib/meteorology/providers/yr.rb +89 -0
- data/lib/meteorology/temperature.rb +14 -0
- data/lib/meteorology/weather.rb +10 -0
- data/lib/meteorology/weather_collection.rb +12 -0
- data/spec/meteorology/providers/yr_spec.rb +33 -0
- data/spec/meteorology/temperature_spec.rb +21 -0
- data/spec/meteorology/weather_collection_spec.rb +42 -0
- data/spec/meteorology/weather_spec.rb +17 -0
- data/spec/meteorology_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- metadata +122 -0
data/lib/meteorology.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'libxml'
|
3
|
+
require 'time'
|
4
|
+
require 'uri'
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
require 'meteorology/weather_collection'
|
8
|
+
require 'meteorology/weather'
|
9
|
+
require 'meteorology/temperature'
|
10
|
+
require 'meteorology/providers'
|
11
|
+
|
12
|
+
module Meteorology
|
13
|
+
def self.included(klass)
|
14
|
+
klass.send(:include, InstanceMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
def weather
|
19
|
+
# Just assumes #latitude and #longitude for now
|
20
|
+
# Also just assumes Yr.no
|
21
|
+
@weather ||= Meteorology::Providers::Yr.new.load(latitude, longitude)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Meteorology
|
2
|
+
module Providers
|
3
|
+
class Yr
|
4
|
+
|
5
|
+
URL = "http://api.yr.no/weatherapi/locationforecast/1.6/?lat=%s;lon=%s"
|
6
|
+
|
7
|
+
def load(lat, lng)
|
8
|
+
parser = LibXML::XML::SaxParser.string(Net::HTTP.get(URI.parse(URL % [lat, lng])))
|
9
|
+
parser.callbacks = XmlParser.new
|
10
|
+
parser.parse
|
11
|
+
return parser.callbacks.forecasts
|
12
|
+
end
|
13
|
+
|
14
|
+
class XmlParser
|
15
|
+
attr_accessor :forecasts
|
16
|
+
|
17
|
+
ATTR_MAPPING = {
|
18
|
+
'fog' => :percent,
|
19
|
+
'pressure' => :value,
|
20
|
+
'highClouds' => :percent,
|
21
|
+
'windDirection' => :name,
|
22
|
+
'mediumClouds' => :percent,
|
23
|
+
'windSpeed' => :mps,
|
24
|
+
'cloudiness' => :percent,
|
25
|
+
'lowClouds' => :percent,
|
26
|
+
'humidity' => :value,
|
27
|
+
'temperature' => :value,
|
28
|
+
'symbol' => :number,
|
29
|
+
'precipitation' => :value,
|
30
|
+
'temperatureProbability' => :value,
|
31
|
+
'windProbability' => :value,
|
32
|
+
'symbolProbability' => :value
|
33
|
+
}
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@forecasts = WeatherCollection.new
|
37
|
+
@location = 0
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_missing(*args)
|
41
|
+
#dont care
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_start_element(element, attributes)
|
45
|
+
case element
|
46
|
+
when 'time'
|
47
|
+
if new_period?(attributes)
|
48
|
+
key = Time.parse(attributes['from'])
|
49
|
+
@current_period = @forecasts[key] = Meteorology::Weather.new(key)
|
50
|
+
end
|
51
|
+
when 'location'
|
52
|
+
if @current_period
|
53
|
+
@location += 1
|
54
|
+
end
|
55
|
+
else
|
56
|
+
if @current_period && @location <= 2
|
57
|
+
read_value(element, attributes)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def read_value(element, attributes)
|
63
|
+
case element
|
64
|
+
when 'temperature'
|
65
|
+
@current_period.temperature = Meteorology::Temperature.new(attributes['unit'].to_sym, attributes['value'])
|
66
|
+
else
|
67
|
+
method = "#{element}="
|
68
|
+
@current_period.send(method, attributes[ATTR_MAPPING[element].to_s]) if @current_period.respond_to?(method)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def on_end_element(element)
|
73
|
+
if element == 'location' && @location == 2
|
74
|
+
# Done with one period
|
75
|
+
@location = 0
|
76
|
+
@current_period = nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def new_period?(attributes)
|
81
|
+
attributes['from'] == attributes['to']
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Meteorology
|
2
|
+
class Temperature
|
3
|
+
def initialize(system, degrees)
|
4
|
+
raise ArgumentError.new("Need :farenheit or :celcius") unless [:farenheit, :celcius].include? system
|
5
|
+
|
6
|
+
@degrees = degrees
|
7
|
+
@system = system
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"#{@degrees} #{@system.to_s[0,1].upcase}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Meteorology::Providers::Yr" do
|
4
|
+
it "exists, d'uh" do
|
5
|
+
lambda{Meteorology::Providers::Yr}.should_not raise_error(NameError)
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'parsing' do
|
9
|
+
before(:all) do
|
10
|
+
@yr = Meteorology::Providers::Yr.new
|
11
|
+
@lat = 59.9
|
12
|
+
@lng = 10.75
|
13
|
+
|
14
|
+
FakeWeb.allow_net_connect = false
|
15
|
+
FakeWeb.register_uri(:get,
|
16
|
+
Meteorology::Providers::Yr::URL % [@lat, @lng],
|
17
|
+
:body => File.read($fixture_dir + '/yr.no/locationforecast-1.6.xml'))
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
after(:all) do
|
22
|
+
FakeWeb.allow_net_connect = true
|
23
|
+
FakeWeb.clean_registry
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'parses yr xml files to a WeatherCollection' do
|
27
|
+
wc = @yr.load(59.9, 10.75)
|
28
|
+
wc.should be_instance_of(Meteorology::WeatherCollection)
|
29
|
+
wc.size.should == 87
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Meteorology::Temperature" do
|
4
|
+
it "exists, d'uh" do
|
5
|
+
lambda{Meteorology::Temperature}.should_not raise_error(NameError)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'is instantiated with :farenheit or :celcuis and the degree' do
|
9
|
+
lambda {temp = Meteorology::Temperature.new(:celcius, 10)}.should_not raise_error(ArgumentError)
|
10
|
+
lambda {temp = Meteorology::Temperature.new(:farenheit, 100)}.should_not raise_error(ArgumentError)
|
11
|
+
|
12
|
+
lambda {temp = Meteorology::Temperature.new(:foo, 100)}.should raise_error(ArgumentError)
|
13
|
+
lambda {temp = Meteorology::Temperature.new(10)}.should raise_error(ArgumentError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'pretty prints' do
|
17
|
+
Meteorology::Temperature.new(:celcius, 10).to_s.should == "10 C"
|
18
|
+
Meteorology::Temperature.new(:farenheit, 100).to_s.should == "100 F"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Meteorology::WeatherCollection' do
|
4
|
+
it "exists, d'uh" do
|
5
|
+
lambda{Meteorology::WeatherCollection}.should_not raise_error(NameError)
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
@wc = Meteorology::WeatherCollection.new
|
10
|
+
24.times do |i|
|
11
|
+
time = Time.utc(2009, 10, 20, i, 0, 0)
|
12
|
+
@wc[time] = Meteorology::Weather.new(time)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'approximates to closest hour' do
|
17
|
+
Time.stub!(:now).and_return(Time.utc(2009, 4, 29, 2, 27, 0))
|
18
|
+
@wc.send(:current_time_key).should == Time.utc(2009, 4, 29, 2, 0, 0)
|
19
|
+
|
20
|
+
Time.stub!(:now).and_return(Time.utc(2009, 4, 29, 2, 31, 0))
|
21
|
+
@wc.send(:current_time_key).should == Time.utc(2009, 4, 29, 3, 0, 0)
|
22
|
+
|
23
|
+
Time.stub!(:now).and_return(Time.utc(2009, 4, 29, 23, 45, 0))
|
24
|
+
@wc.send(:current_time_key).should == Time.utc(2009, 4, 30, 0, 0, 0)
|
25
|
+
|
26
|
+
Time.stub!(:now).and_return(Time.utc(2009, 12, 31, 23, 45, 0))
|
27
|
+
@wc.send(:current_time_key).should == Time.utc(2010, 1, 1, 0, 0, 0)
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'provides the #current weather on closest hour' do
|
32
|
+
@wc.should respond_to(:current)
|
33
|
+
|
34
|
+
time_now = Time.utc(2009, 10, 20, 12, 27, 0)
|
35
|
+
Time.stub!(:now).and_return(time_now)
|
36
|
+
|
37
|
+
current = @wc.current
|
38
|
+
current.should be_instance_of(Meteorology::Weather)
|
39
|
+
current.time.should == Time.utc(2009, 10, 20, 12, 00, 0)
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Meteorology::Weather" do
|
4
|
+
it "exists, d'uh" do
|
5
|
+
lambda{Meteorology::Weather}.should_not raise_error(NameError)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'accepts String or Time for time on #initialize' do
|
9
|
+
Meteorology::Weather.new("2009-01-01").time.should be_instance_of(Time)
|
10
|
+
Meteorology::Weather.new(Time.now).time.should be_instance_of(Time)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'reports #temperature' do
|
14
|
+
w = Meteorology::Weather.new(Time.now.to_s)
|
15
|
+
w.should respond_to(:temperature)
|
16
|
+
end
|
17
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'meteorology'
|
4
|
+
|
5
|
+
require 'spec/autorun'
|
6
|
+
|
7
|
+
require 'fakeweb'
|
8
|
+
|
9
|
+
Spec::Runner.configure do |config|
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
$fixture_dir = File.join(File.dirname(__FILE__), '..', 'fixtures')
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meteorology
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rune Botten
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-20 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: cucumber
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: fakeweb
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.6
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: libxml-ruby
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.1.3
|
54
|
+
version:
|
55
|
+
description: "Adds #weather method to ruby objects that know where they are in the world. Simple."
|
56
|
+
email: rbotten@gmail.com
|
57
|
+
executables: []
|
58
|
+
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files:
|
62
|
+
- LICENSE
|
63
|
+
- README.rdoc
|
64
|
+
files:
|
65
|
+
- .document
|
66
|
+
- .gitignore
|
67
|
+
- LICENSE
|
68
|
+
- README.rdoc
|
69
|
+
- Rakefile
|
70
|
+
- VERSION
|
71
|
+
- features/meteorology.feature
|
72
|
+
- features/step_definitions/meteorology_steps.rb
|
73
|
+
- features/support/env.rb
|
74
|
+
- fixtures/yr.no/locationforecast-1.6.xml
|
75
|
+
- lib/meteorology.rb
|
76
|
+
- lib/meteorology/providers.rb
|
77
|
+
- lib/meteorology/providers/yr.rb
|
78
|
+
- lib/meteorology/temperature.rb
|
79
|
+
- lib/meteorology/weather.rb
|
80
|
+
- lib/meteorology/weather_collection.rb
|
81
|
+
- spec/meteorology/providers/yr_spec.rb
|
82
|
+
- spec/meteorology/temperature_spec.rb
|
83
|
+
- spec/meteorology/weather_collection_spec.rb
|
84
|
+
- spec/meteorology/weather_spec.rb
|
85
|
+
- spec/meteorology_spec.rb
|
86
|
+
- spec/spec.opts
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
has_rdoc: true
|
89
|
+
homepage: http://github.com/runeb/meteorology
|
90
|
+
licenses: []
|
91
|
+
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options:
|
94
|
+
- --charset=UTF-8
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0"
|
102
|
+
version:
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
version:
|
109
|
+
requirements: []
|
110
|
+
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 1.3.5
|
113
|
+
signing_key:
|
114
|
+
specification_version: 3
|
115
|
+
summary: Come rain or shine, geocoded Ruby objects know it
|
116
|
+
test_files:
|
117
|
+
- spec/meteorology/providers/yr_spec.rb
|
118
|
+
- spec/meteorology/temperature_spec.rb
|
119
|
+
- spec/meteorology/weather_collection_spec.rb
|
120
|
+
- spec/meteorology/weather_spec.rb
|
121
|
+
- spec/meteorology_spec.rb
|
122
|
+
- spec/spec_helper.rb
|