weather_data 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1cd482e05d0bd9499c8e5384e655717cb70b434f
4
+ data.tar.gz: fe495d208cba3e096ecf7025b70c629374d2820f
5
+ SHA512:
6
+ metadata.gz: 4a30928855e482408e32d32b8ef5dbbfec633a38564a587baafe4d0bd5b03dc0c0d46208c80a5eb5fa710fe4dc4e688b266234481bc56f5b5db27ebe0d395f22
7
+ data.tar.gz: 0261711b5709412fe77c1ba769504e2c6283287bf12d5c1e0e8688784dc59412cb88774e0bfd99592a6c8b888a1407dcc214b29068941baac0ab322e9737b86e
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rspec
19
+ .ruby-gemset
20
+ .ruby-version
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ script:
3
+ - bundle exec rake spec
4
+ rvm:
5
+ - 1.8.7
6
+ - ree
7
+ - 1.9.2
8
+ - 1.9.3
9
+ - 2.0.0
10
+ - ruby-head
11
+ - rbx-18mode
12
+ - rbx-19mode
13
+ - jruby
14
+ - jruby-18mode
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in weather_data.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andrew Slotin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ [![Build Status](https://travis-ci.org/andrewslotin/weather_data.png)](https://travis-ci.org/andrewslotin/weather_data)
2
+
3
+ # WeatherData
4
+
5
+ TODO: Write a gem description
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'weather_data'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install weather_data
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
@@ -0,0 +1,8 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require "weather_data/version"
4
+ require "weather_data/weather"
5
+
6
+ module WeatherData
7
+
8
+ end
@@ -0,0 +1,18 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require "weather_data/humidity/relative"
4
+
5
+ module WeatherData
6
+ module Humidity
7
+ def self.parse(s)
8
+ _, points, units = /\b(\d+(?:\.\d+)?)%/.match(s).to_a
9
+
10
+ raise ArgumentError.new(%Q{"#{s.inspect}" doesn't contain humidity}) unless points
11
+
12
+ percents = points.to_f
13
+ raise ArgumentError.new("Invalid value for relative humidity: #{percents.inspect}") unless percents > 0 && percents <= 100
14
+
15
+ Relative.new(percents)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'delegate'
4
+
5
+ module WeatherData
6
+ module Humidity
7
+ class Relative < ::SimpleDelegator
8
+ def initialize(points)
9
+ super points.to_f
10
+ end
11
+
12
+ def to_s
13
+ "#{percentage}%"
14
+ end
15
+
16
+ protected
17
+
18
+ def percentage
19
+ __getobj__
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,55 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require "weather_data/temperature/base"
4
+ require "weather_data/temperature/celsius"
5
+ require "weather_data/temperature/fahrenheit"
6
+ require "weather_data/temperature/kelvin"
7
+
8
+ module WeatherData
9
+ module Temperature
10
+ extend self
11
+
12
+ CELSIUS = :C
13
+ FAHRENHEIT = :F
14
+ KELVIN = :K
15
+
16
+ def parse(s)
17
+ degrees, units = s.match(/([+-]?\d+(?:\.\d+)?)\s*(°?#{CELSIUS}|°?#{FAHRENHEIT}|#{KELVIN})\b/u).to_a[1..2]
18
+
19
+ raise ArgumentError.new(%Q{"#{s}" doesn't contain temperature}) unless degrees && units
20
+
21
+ units_class(units).new(degrees.to_f)
22
+ end
23
+
24
+ module HelperMethods
25
+ def celsius
26
+ Celsius.new(self)
27
+ end
28
+
29
+ def fahrenheit
30
+ Fahrenheit.new(self)
31
+ end
32
+
33
+ def kelvin
34
+ Kelvin.new(self)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def units_class(units)
41
+ case units.gsub(/\A°/, '').to_sym
42
+ when CELSIUS
43
+ Celsius
44
+ when FAHRENHEIT
45
+ Fahrenheit
46
+ when KELVIN
47
+ Kelvin
48
+ else
49
+ raise ArgumentError.new(units)
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ [Integer, Float].each { |klass| klass.send :include, WeatherData::Temperature::HelperMethods }
@@ -0,0 +1,69 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module WeatherData
4
+ module Temperature
5
+ class Base
6
+ include Comparable
7
+
8
+ attr_accessor :degrees
9
+
10
+ def initialize(deg)
11
+ @degrees = if deg.is_a? Numeric
12
+ deg
13
+ else
14
+ to_self(deg).degrees
15
+ end
16
+ end
17
+
18
+ def ==(value)
19
+ if value.is_a? Numeric
20
+ degrees == value
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def degrees
27
+ @degrees.to_f
28
+ end
29
+
30
+ def -@
31
+ self.class.new(-degrees)
32
+ end
33
+
34
+ def <=>(value)
35
+ degrees <=> to_self(value).degrees
36
+ end
37
+
38
+ def +(value)
39
+ self.class.new(degrees + to_self(value).degrees)
40
+ end
41
+
42
+ def -(value)
43
+ -(-self + value)
44
+ end
45
+
46
+ def *(value)
47
+ self.class.new(value * degrees)
48
+ end
49
+
50
+ def /(value)
51
+ self.class.new(value * (1 / degrees))
52
+ end
53
+
54
+ def to_i
55
+ degrees.round
56
+ end
57
+
58
+ def to_f
59
+ degrees
60
+ end
61
+
62
+ private
63
+
64
+ def to_self(value)
65
+ value
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module WeatherData
4
+ module Temperature
5
+ class Celsius < Base
6
+ def to_celsius
7
+ self
8
+ end
9
+
10
+ def to_fahrenheit
11
+ Fahrenheit.new(degrees * 9.0 / 5 + 32)
12
+ end
13
+
14
+ def to_kelvin
15
+ Kelvin.new(degrees + 273.15)
16
+ end
17
+
18
+ def to_s
19
+ "#{degrees}°C"
20
+ end
21
+
22
+ private
23
+
24
+ def to_self(value)
25
+ raise ArgumentError unless value.respond_to? :to_celsius
26
+ value.to_celsius
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module WeatherData
4
+ module Temperature
5
+ class Fahrenheit < Base
6
+ def to_celsius
7
+ Celsius.new((degrees - 32) * 5.0 / 9)
8
+ end
9
+
10
+ def to_fahrenheit
11
+ self
12
+ end
13
+
14
+ def to_kelvin
15
+ to_celsius.to_kelvin
16
+ end
17
+
18
+ def to_s
19
+ "#{degrees}°F"
20
+ end
21
+
22
+ private
23
+
24
+ def to_self(value)
25
+ raise ArgumentError unless value.respond_to? :to_fahrenheit
26
+ value.to_fahrenheit
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module WeatherData
4
+ module Temperature
5
+ class Kelvin < Base
6
+ def initialize(deg)
7
+ super
8
+
9
+ @degrees = 0 if @degrees < 0
10
+ end
11
+
12
+ def to_celsius
13
+ Celsius.new(degrees - 273.15)
14
+ end
15
+
16
+ def to_fahrenheit
17
+ to_celsius.to_fahrenheit
18
+ end
19
+
20
+ def to_kelvin
21
+ self
22
+ end
23
+
24
+ def to_s
25
+ "#{degrees}"
26
+ end
27
+
28
+ private
29
+
30
+ def to_self(value)
31
+ raise ArgumentError unless value.respond_to? :to_kelvin
32
+ value.to_kelvin
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module WeatherData
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,105 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require "weather_data/temperature"
4
+ require "weather_data/humidity"
5
+ require "weather_data/wind"
6
+
7
+ module WeatherData
8
+ class Weather
9
+ ATTRIBUTES = [
10
+ :temperature,
11
+ :humidity,
12
+ :wind
13
+ ].freeze
14
+
15
+ attr_accessor *ATTRIBUTES
16
+
17
+ def self.parse(s)
18
+ attributes = {}.tap do |attrs|
19
+ {
20
+ :temperature => Temperature,
21
+ :humidity => Humidity,
22
+ :wind => Wind
23
+ }.each do |attr, parser|
24
+ begin
25
+ attrs[attr] = parser.parse(s)
26
+ rescue ArgumentError
27
+ end
28
+ end
29
+ end
30
+
31
+ raise ArgumentError.new(%Q{"#{s}" doesn't contain weather data}) if attributes.empty?
32
+
33
+ new(attributes)
34
+ end
35
+
36
+ def initialize(attributes = {})
37
+ ATTRIBUTES.each do |attr|
38
+ self.send(:"#{attr}=", attributes[attr])
39
+ end
40
+ end
41
+
42
+ def dew_point
43
+ if humidity && temperature
44
+ t = temperature.to_celsius.degrees
45
+ a, b, c = magnus_formula_constants(t)
46
+ gamma = Math.log(humidity / 100) + b * t / (c + t)
47
+
48
+ Temperature::Celsius.new(c * gamma / (b - gamma))
49
+ end
50
+ end
51
+
52
+ def vapour_pressure
53
+ if humidity
54
+ t = temperature.to_celsius.degrees
55
+ (humidity / 100.0) * 6.105 * Math.exp(17.27 * t / (237.7 + t))
56
+ end
57
+ end
58
+
59
+ def humindex
60
+ if temperature && dew_point
61
+ t = temperature.to_celsius.degrees + 0.5555 * (6.11 * Math.exp(5417.753 * (1 / 273.16 - 1 / dew_point.to_kelvin.degrees)) - 10)
62
+ t.celsius
63
+ end
64
+ end
65
+
66
+ def apparent_temperature
67
+ if vapour_pressure && temperature
68
+ t = temperature.to_celsius.degrees
69
+ Temperature::Celsius.new(t + 0.33 * vapour_pressure - 0.7 * wind.to_f - 4.0)
70
+ end
71
+ end
72
+
73
+ def temperature=(value)
74
+ @temperature = case value
75
+ when String
76
+ Temperature.parse(value)
77
+ when Temperature::Base
78
+ value
79
+ else
80
+ raise ArgumentError.new(%Q{#{value.inspect} must be String or kind of WeatherData::Temperature::Base})
81
+ end
82
+ end
83
+
84
+ def humidity=(value)
85
+ @humidity = case value
86
+ when String
87
+ Humidity.parse(value)
88
+ when Humidity::Relative
89
+ value
90
+ else
91
+ raise ArgumentError.new(%Q{#{value.inspect} must be String or an instance of WeatherData::Humidity::Relative})
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def magnus_formula_constants(temperature)
98
+ if temperature > 0
99
+ [6.1121, 17.368, 238.88]
100
+ else
101
+ [6.1121, 17.966, 247.15]
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,99 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'delegate'
4
+
5
+ module WeatherData
6
+ class Wind < ::SimpleDelegator
7
+ ATTRIBUTES = [
8
+ :direction,
9
+ :speed
10
+ ].freeze
11
+
12
+ CARDINAL_DIRECTIONS = {
13
+ :N => 0.0,
14
+ :NNE => 22.5,
15
+ :NE => 45.0,
16
+ :ENE => 67.5,
17
+ :E => 90.0,
18
+ :ESE => 112.5,
19
+ :SE => 135.0,
20
+ :SSE => 157.5,
21
+ :S => 180.0,
22
+ :SSW => 202.5,
23
+ :SW => 225.0,
24
+ :WSW => 247.5,
25
+ :W => 270.0,
26
+ :WNW => 292.5,
27
+ :NW => 315.0,
28
+ :NNW => 337.5
29
+ }.freeze
30
+
31
+ attr_accessor *ATTRIBUTES
32
+
33
+ def self.parse(s)
34
+ _, speed, units = /(\d+(?:\.\d+)?)\s*(m\/?s(?:ec)?|km\/?h(?:our)?)/i.match(s).to_a
35
+ units ||= "m/s"
36
+
37
+ raise ArgumentError.new(%Q{"#{s.inspect}" doesn't contain wind speed}) unless speed
38
+
39
+ _, direction = /(#{CARDINAL_DIRECTIONS.keys.join('|')})/.match(s).to_a
40
+
41
+ new(speed.to_f, units, direction)
42
+ end
43
+
44
+ def initialize(speed, units = "m/s", azimuth_or_direction = nil)
45
+ super normalize_speed(speed, units)
46
+ @direction = to_direction(azimuth_or_direction) if azimuth_or_direction
47
+ end
48
+
49
+ def speed
50
+ __getobj__
51
+ end
52
+
53
+ def speed=(value)
54
+ __setobj__(value)
55
+ end
56
+
57
+ def units
58
+ 'm/s'
59
+ end
60
+
61
+ def to_kmh
62
+ speed * 3.6
63
+ end
64
+
65
+ def to_s
66
+ ["#{speed} #{units}", direction].compact.join(" ")
67
+ end
68
+
69
+ protected
70
+
71
+ def normalize_speed(speed, units)
72
+ if units.downcase.gsub('/', '') == 'kmh'
73
+ speed / 3.6
74
+ else
75
+ speed
76
+ end
77
+ end
78
+
79
+ def to_direction(azimuth_or_direction)
80
+ if azimuth_or_direction.is_a? Numeric
81
+ d = (azimuth_or_direction + 360) % 360
82
+
83
+ unless d >= 0 && d < 360
84
+ raise ArgumentError.new("Invalid azimuth for wind direction: #{azimuth_or_direction.inspect}")
85
+ end
86
+
87
+ CARDINAL_DIRECTIONS.find { |direction, azimuth| (d - azimuth).abs < 22.5 }.first
88
+ else
89
+ d = azimuth_or_direction.upcase.gsub('/', '').to_sym
90
+
91
+ unless CARDINAL_DIRECTIONS.has_key? d
92
+ raise ArgumentError.new("Invalid azimuth for wind direction: #{azimuth_or_direction.inspect}")
93
+ end
94
+
95
+ d
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,10 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+
6
+ require 'weather_data'
7
+
8
+ RSpec.configure do |config|
9
+
10
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe WeatherData::Humidity do
6
+ describe ".parse" do
7
+ it "returns an initialized instance of WeatherData::RelativeHumidity" do
8
+ h = described_class.parse("Humidity: 80%")
9
+
10
+ expect(h).to be_kind_of WeatherData::Humidity::Relative
11
+ expect(h).to eq 80
12
+ end
13
+
14
+ context "if given string does not contain humidity" do
15
+ it "raises ArgumentError" do
16
+ expect { described_class.parse("string") }.to raise_error ArgumentError
17
+ end
18
+ end
19
+
20
+ context "if given value 0% or less" do
21
+ it "raises ArgumentError" do
22
+ expect { described_class.parse("0%") }.to raise_error ArgumentError
23
+ end
24
+ end
25
+
26
+ context "if given value greater than 100%" do
27
+ it "raises ArgumentError" do
28
+ expect { described_class.parse("101%") }.to raise_error ArgumentError
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe WeatherData::Temperature::Base do
4
+ subject { WeatherData::Temperature::Base.new(10) }
5
+
6
+ shared_examples_for "returning new instance" do
7
+ it do
8
+ expect(subject.send(method_name, subject)).not_to eql subject
9
+ end
10
+ end
11
+
12
+ describe "#+" do
13
+ it_should_behave_like "returning new instance" do
14
+ let(:method_name) { :+ }
15
+ end
16
+
17
+ it "converts given value" do
18
+ subject.should_receive(:to_self).with(subject).and_return(subject)
19
+
20
+ subject + subject
21
+ end
22
+
23
+ it "returns sum of degrees" do
24
+ expect((subject + subject).degrees).to eq 20
25
+ end
26
+ end
27
+
28
+ describe "#-" do
29
+ it_should_behave_like "returning new instance" do
30
+ let(:method_name) { :- }
31
+ end
32
+
33
+ it "returns dfference between degrees" do
34
+ expect((subject - subject).degrees).to eq 0
35
+ end
36
+ end
37
+
38
+ describe "#*" do
39
+ it_should_behave_like "returning new instance" do
40
+ let(:method_name) { :* }
41
+ end
42
+
43
+ it "returns degrees multiplied by value" do
44
+ expect((subject * 10).degrees).to eq 100
45
+ end
46
+ end
47
+
48
+ describe "#/" do
49
+ it_should_behave_like "returning new instance" do
50
+ let(:method_name) { :/ }
51
+ end
52
+
53
+ it "returns degrees divided by value" do
54
+ expect((subject / 10).degrees).to eq 1
55
+ end
56
+ end
57
+
58
+ describe "#==" do
59
+ subject { WeatherData::Temperature::Base }
60
+
61
+ it "can be compared to Numeric" do
62
+ expect(subject.new(10) == 10).to be_true
63
+ expect(subject.new(10) == 10.0).to be_true
64
+ expect(subject.new(10) == 11).to be_false
65
+ end
66
+ end
67
+
68
+ describe "#to_i" do
69
+ subject { WeatherData::Temperature::Base }
70
+
71
+ it "returns degrees rounded" do
72
+ expect(subject.new(15.6).to_i).to eq 16
73
+ expect(subject.new(15.1).to_i).to eq 15
74
+ end
75
+ end
76
+
77
+ describe "#to_f" do
78
+ subject { WeatherData::Temperature::Base }
79
+
80
+ it "returns degrees" do
81
+ expect(subject.new(15.6).to_f).to eq 15.6
82
+ expect(subject.new(15.1).to_f).to eq 15.1
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe WeatherData::Temperature::Celsius do
4
+ subject { WeatherData::Temperature::Celsius.new(0) }
5
+
6
+ describe "#to_celsius" do
7
+ it "returns self" do
8
+ expect(subject.to_celsius).to eq subject
9
+ end
10
+ end
11
+
12
+ describe "#to_fahrenheit" do
13
+ it "returns degrees in Fahrenheit" do
14
+ expect(subject.to_fahrenheit).to eq 32
15
+ end
16
+ end
17
+
18
+ describe "#to_kelvin" do
19
+ it "returns degrees in Kelvin" do
20
+ expect(subject.to_kelvin).to eq 273.15
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe WeatherData::Temperature::Fahrenheit do
4
+ subject { WeatherData::Temperature::Fahrenheit.new(32) }
5
+
6
+ describe "#to_celsius" do
7
+ it "returns degrees in Celsius" do
8
+ expect(subject.to_celsius).to eq 0
9
+ end
10
+ end
11
+
12
+ describe "#to_fahrenheit" do
13
+ it "returns self" do
14
+ expect(subject.to_fahrenheit).to eq subject
15
+ end
16
+ end
17
+
18
+ describe "#to_kelvin" do
19
+ it "returns degrees in Kelvin" do
20
+ expect(subject.to_kelvin).to eq 273.15
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe WeatherData::Temperature::Kelvin do
4
+ subject { WeatherData::Temperature::Kelvin.new(273.15) }
5
+
6
+ describe "#to_celsius" do
7
+ it "returns degrees in Celsius" do
8
+ expect(subject.to_celsius).to eq 0
9
+ end
10
+ end
11
+
12
+ describe "#to_fahrenheit" do
13
+ it "returns degrees in Fahrenheit" do
14
+ expect(subject.to_fahrenheit).to eq 32
15
+ end
16
+ end
17
+
18
+ describe "#to_kelvin" do
19
+ it "returns self" do
20
+ expect(subject.to_kelvin).to eq subject
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,60 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe WeatherData::Temperature do
6
+ [0, 0.0].each do |number|
7
+ describe "extends #{number.class}" do
8
+ {
9
+ :celsius => WeatherData::Temperature::Celsius,
10
+ :fahrenheit => WeatherData::Temperature::Fahrenheit,
11
+ :kelvin => WeatherData::Temperature::Kelvin
12
+ }.each do |method_name, klass|
13
+ it "adds #{method_name}" do
14
+ expect(number).to respond_to(method_name)
15
+ end
16
+
17
+ it "#{method_name} returns an instance of #{klass.name}" do
18
+ expect(number.send(method_name)).to be_kind_of klass
19
+ expect(number.send(method_name).degrees).to eq number
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "#parse" do
26
+ it "parses temperature in Celsius" do
27
+ [15.2, -15.2].each do |deg|
28
+ ["#{deg} °C", "#{deg}°C", "#{deg}C", "#{deg} C", "Temperature: #{deg}°C"].each do |s|
29
+ t = subject.parse(s)
30
+ expect(t).to be_kind_of WeatherData::Temperature::Celsius
31
+ expect(t).to eq deg
32
+ end
33
+ end
34
+ end
35
+
36
+ it "parses temperature in Fahrenheit" do
37
+ [15.2, -15.2].each do |deg|
38
+ ["#{deg} °F", "#{deg}°F", "#{deg}F", "#{deg} F", "Temperature: #{deg}°F"].each do |s|
39
+ t = subject.parse(s)
40
+ expect(t).to be_kind_of WeatherData::Temperature::Fahrenheit
41
+ expect(t).to eq deg
42
+ end
43
+ end
44
+ end
45
+
46
+ it "parses temperature in Kelvin" do
47
+ ["15.2K", "15.2 K"].each do |s|
48
+ t = subject.parse(s)
49
+ expect(t).to be_kind_of WeatherData::Temperature::Kelvin
50
+ expect(t).to eq 15.2
51
+ end
52
+ end
53
+
54
+ context "when there is no temperature within given string" do
55
+ it "raises ArgumentError" do
56
+ expect { subject.parse("bogus string") }.to raise_error ArgumentError
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe WeatherData do
6
+ subject { WeatherData }
7
+
8
+ it { expect(subject::VERSION).to eq '0.0.1' }
9
+ end
@@ -0,0 +1,57 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe WeatherData::Weather do
6
+ subject { described_class.new(:temperature => "+30C", :humidity => "60%") }
7
+
8
+ describe ".parse" do
9
+ it "returns an instance of WeatherData::Weather" do
10
+ expect(described_class.parse("10C, 40%")).to be_an_instance_of described_class
11
+ end
12
+
13
+ it "initializes temperature" do
14
+ expect(described_class.parse("10C, 40%").temperature).to eq 10
15
+ end
16
+
17
+ it "initializes humidity" do
18
+ expect(described_class.parse("10C, 40%").humidity).to eq 40
19
+ end
20
+ end
21
+
22
+ describe "#dew_point" do
23
+ it "returns dew point based on Magnus formula" do
24
+ expect(subject.dew_point.to_celsius.degrees.round).to eq 21
25
+ end
26
+ end
27
+
28
+ describe "#humindex" do
29
+ before do
30
+ subject.stub(:dew_point).and_return WeatherData::Temperature::Celsius.new(15)
31
+ end
32
+
33
+ it "returns humindex" do
34
+ expect(subject.humindex.to_celsius.degrees.round).to eq 34
35
+ end
36
+ end
37
+
38
+ describe "#vapour_pressure" do
39
+ it "returns vapour pressure in hPa for given conditions" do
40
+ expect(subject.vapour_pressure.round).to eq ((42 * subject.humidity / 100.0).round)
41
+ end
42
+ end
43
+
44
+ describe "#apparent_temperature" do
45
+ before do
46
+ subject.stub(
47
+ :temperature => WeatherData::Temperature::Celsius.new(18),
48
+ :humidity => WeatherData::Humidity::Relative.new(70),
49
+ :wind => WeatherData::Wind.new(10, "km/h")
50
+ )
51
+ end
52
+
53
+ it "returns Australian apparent temperature for given conditions" do
54
+ expect(subject.apparent_temperature.to_celsius.degrees.round).to eq 17
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe WeatherData::Wind do
6
+ subject { described_class.new(1) }
7
+
8
+ describe ".parse" do
9
+ end
10
+
11
+ describe "#initialize" do
12
+ end
13
+
14
+ describe "#to_kmh" do
15
+ it "returns speed in km/h" do
16
+ expect(subject.to_kmh).to eq 3.6
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'weather_data/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "weather_data"
8
+ gem.version = WeatherData::VERSION
9
+ gem.authors = ["Andrew Slotin"]
10
+ gem.email = ["andrew.slotin@gmail.com"]
11
+ gem.description = %q{Simple weather data manipulation}
12
+ gem.summary = %q{Provides conversion between temperature units etc.}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency('rake')
21
+ gem.add_development_dependency('rspec')
22
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: weather_data
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Slotin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Simple weather data manipulation
42
+ email:
43
+ - andrew.slotin@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .travis.yml
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - lib/weather_data.rb
55
+ - lib/weather_data/humidity.rb
56
+ - lib/weather_data/humidity/relative.rb
57
+ - lib/weather_data/temperature.rb
58
+ - lib/weather_data/temperature/base.rb
59
+ - lib/weather_data/temperature/celsius.rb
60
+ - lib/weather_data/temperature/fahrenheit.rb
61
+ - lib/weather_data/temperature/kelvin.rb
62
+ - lib/weather_data/version.rb
63
+ - lib/weather_data/weather.rb
64
+ - lib/weather_data/wind.rb
65
+ - spec/spec_helper.rb
66
+ - spec/weather_data/humidity_spec.rb
67
+ - spec/weather_data/temperature/base_spec.rb
68
+ - spec/weather_data/temperature/celsius_spec.rb
69
+ - spec/weather_data/temperature/fahrenheit_spec.rb
70
+ - spec/weather_data/temperature/kelvin_spec.rb
71
+ - spec/weather_data/temperature_spec.rb
72
+ - spec/weather_data/version_spec.rb
73
+ - spec/weather_data/weather_spec.rb
74
+ - spec/weather_data/wind_spec.rb
75
+ - weather_data.gemspec
76
+ homepage: ''
77
+ licenses: []
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.0.2
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Provides conversion between temperature units etc.
99
+ test_files:
100
+ - spec/spec_helper.rb
101
+ - spec/weather_data/humidity_spec.rb
102
+ - spec/weather_data/temperature/base_spec.rb
103
+ - spec/weather_data/temperature/celsius_spec.rb
104
+ - spec/weather_data/temperature/fahrenheit_spec.rb
105
+ - spec/weather_data/temperature/kelvin_spec.rb
106
+ - spec/weather_data/temperature_spec.rb
107
+ - spec/weather_data/version_spec.rb
108
+ - spec/weather_data/weather_spec.rb
109
+ - spec/weather_data/wind_spec.rb