forecast 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.gitignore +11 -1
- data/CHANGELOG.md +27 -0
- data/README.md +196 -8
- data/bin/forecast +94 -0
- data/forecast.gemspec +4 -3
- data/lib/forecast/adapter.rb +126 -123
- data/lib/forecast/adapters/forecast_io_adapter.rb +57 -0
- data/lib/forecast/adapters/open_weather_map_adapter.rb +41 -58
- data/lib/forecast/adapters/wunderground_adapter.rb +53 -29
- data/lib/forecast/adapters/yahoo_adapter.rb +21 -29
- data/lib/forecast/collection.rb +4 -4
- data/lib/forecast/conditions.yml +2 -2
- data/lib/forecast/config.rb +4 -5
- data/lib/forecast/config.yml +2 -4
- data/lib/forecast/http.rb +80 -0
- data/lib/forecast/synonyms.yml +32 -0
- data/lib/forecast/themes/weather_icons.yml +10 -8
- data/lib/forecast/utils.rb +101 -6
- data/lib/forecast/version.rb +1 -1
- data/lib/forecast.rb +39 -107
- data/spec/fixtures/locations.yml +21 -0
- data/spec/forecast_spec.rb +58 -27
- data/spec/spec_helper.rb +16 -0
- metadata +28 -22
- data/.README.md.html +0 -480
- data/lib/forecast/adapters/open_weather_map_adapter.yml +0 -18
- data/lib/forecast/cache.rb +0 -7
- data/lib/forecast/model.rb +0 -71
@@ -11,21 +11,13 @@ class Forecast
|
|
11
11
|
forecast = nil
|
12
12
|
doc = get_rss(latitude, longitude)
|
13
13
|
if doc
|
14
|
-
|
14
|
+
hash = {}
|
15
15
|
doc.elements.each('rss/channel/item/yweather:condition') do |elem|
|
16
16
|
elem.attributes.each() do |attr|
|
17
|
-
|
18
|
-
value = attr[1]
|
19
|
-
case name
|
20
|
-
when 'date'
|
21
|
-
forecast.date = DateTime.parse(value)
|
22
|
-
when 'temp'
|
23
|
-
forecast.temp = value.to_i
|
24
|
-
when 'text'
|
25
|
-
forecast.condition = get_condition(value)
|
26
|
-
end
|
17
|
+
hash[attr[0].to_sym] = attr[1]
|
27
18
|
end
|
28
19
|
end
|
20
|
+
forecast = get_forecast({latitude: latitude, longitude: longitude}.merge(hash))
|
29
21
|
end
|
30
22
|
return forecast
|
31
23
|
end
|
@@ -40,24 +32,11 @@ class Forecast
|
|
40
32
|
forecasts = Forecast::Collection.new
|
41
33
|
if doc
|
42
34
|
doc.elements.each('rss/channel/item/yweather:forecast') do |elem|
|
43
|
-
|
35
|
+
hash = {}
|
44
36
|
elem.attributes.each() do |attr|
|
45
|
-
|
46
|
-
name = attr[0]
|
47
|
-
value = attr[1]
|
48
|
-
case name
|
49
|
-
when 'date'
|
50
|
-
forecast.date = DateTime.parse(value)
|
51
|
-
when 'low'
|
52
|
-
forecast.temp_min = get_temp(value)
|
53
|
-
when 'high'
|
54
|
-
forecast.temp_max = get_temp(value)
|
55
|
-
when 'text'
|
56
|
-
forecast.condition = get_condition(value)
|
57
|
-
end
|
37
|
+
hash[attr[0].to_sym] = attr[1]
|
58
38
|
end
|
59
|
-
|
60
|
-
forecasts << forecast
|
39
|
+
forecasts << get_forecast({latitude: latitude, longitude: longitude}.merge(hash))
|
61
40
|
end
|
62
41
|
end
|
63
42
|
return forecasts
|
@@ -69,7 +48,7 @@ class Forecast
|
|
69
48
|
woeid = nil
|
70
49
|
query = "SELECT * FROM geo.placefinder WHERE text='#{latitude}, #{longitude}' and gflags='R'"
|
71
50
|
url = URL_YQL + "?q=" + URI::encode(query)
|
72
|
-
doc =
|
51
|
+
doc = get_dom(url)
|
73
52
|
doc.elements.each('query/results/Result/woeid') do |elem|
|
74
53
|
woeid = elem.text
|
75
54
|
end
|
@@ -79,12 +58,25 @@ class Forecast
|
|
79
58
|
def get_rss(latitude, longitude)
|
80
59
|
woeid = get_woeid(latitude, longitude)
|
81
60
|
if woeid
|
82
|
-
doc = get_doc(URL_RSS, {w: woeid})
|
61
|
+
doc = Forecast::Utils.get_doc(URL_RSS, {w: woeid})
|
83
62
|
return doc
|
84
63
|
end
|
85
64
|
return nil
|
86
65
|
end
|
87
66
|
|
67
|
+
def get_forecast(hash)
|
68
|
+
forecast = Forecast.new
|
69
|
+
forecast.latitude = hash[:latitude]
|
70
|
+
forecast.longitude = hash[:longitude]
|
71
|
+
forecast.time = get_time(hash[:date])
|
72
|
+
forecast.condition = get_condition(hash[:text])
|
73
|
+
forecast.text = get_text(hash[:text])
|
74
|
+
forecast.temperature_min = get_temperature(hash[:low])
|
75
|
+
forecast.temperature_max = get_temperature(hash[:high])
|
76
|
+
forecast.temperature = get_temperature(hash.has_key?(:temp) ? hash[:temp] : [hash[:low], hash[:high]])
|
77
|
+
return forecast
|
78
|
+
end
|
79
|
+
|
88
80
|
end
|
89
81
|
end
|
90
82
|
end
|
data/lib/forecast/collection.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
class Forecast
|
2
2
|
class Collection < Array
|
3
|
-
def
|
3
|
+
def select_time(time)
|
4
4
|
result = nil
|
5
5
|
date_forecasts = self.select do |obj|
|
6
|
-
obj.
|
6
|
+
obj.time.to_date == time.to_date
|
7
7
|
end
|
8
8
|
if date_forecasts.length == 0
|
9
9
|
return nil
|
10
10
|
else
|
11
11
|
hour_forecasts = date_forecasts.select do |obj|
|
12
|
-
obj.
|
12
|
+
obj.time.hour == obj.time.hour
|
13
13
|
end
|
14
14
|
if hour_forecasts.length > 0
|
15
15
|
return hour_forecasts.first
|
@@ -17,10 +17,10 @@ class Forecast
|
|
17
17
|
return date_forecasts.first
|
18
18
|
end
|
19
19
|
return nil
|
20
|
-
|
21
20
|
end
|
22
21
|
|
23
22
|
private
|
23
|
+
# Unused
|
24
24
|
def seconds_between(date1, date2)
|
25
25
|
((Time.parse(date1.to_s) - Time.parse(date2.to_s)) / 3600).abs
|
26
26
|
end
|
data/lib/forecast/conditions.yml
CHANGED
data/lib/forecast/config.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
+
require "yaml"
|
1
2
|
class Forecast
|
2
3
|
class Config
|
3
4
|
|
4
|
-
attr_accessor :adapters, :provider, :
|
5
|
+
attr_accessor :adapters, :provider, :scale, :conditions, :synonyms, :cache, :themes, :theme, :config_file
|
5
6
|
|
6
7
|
def initialize
|
7
8
|
|
8
9
|
@config_file = nil
|
9
|
-
|
10
|
-
|
10
|
+
@provider||= :open_weather_map
|
11
11
|
self.load(File.dirname(__FILE__) + '/**/*.yml')
|
12
12
|
|
13
13
|
def theme
|
@@ -21,11 +21,10 @@ class Forecast
|
|
21
21
|
end
|
22
22
|
return @theme
|
23
23
|
end
|
24
|
-
|
25
24
|
end
|
26
25
|
|
26
|
+
|
27
27
|
def load(pattern)
|
28
|
-
# puts 'load forecast pattern ' + pattern.to_s
|
29
28
|
Dir.glob(pattern).sort{ |a, b| a.split(/\//).length <=> b.split(/\//).length}.reverse.each do |f|
|
30
29
|
obj = YAML.load_file(f)
|
31
30
|
# puts 'load forecast config ' + f.to_s
|
data/lib/forecast/config.yml
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'rexml/document'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'json'
|
5
|
+
require "redis"
|
6
|
+
|
7
|
+
class Forecast
|
8
|
+
|
9
|
+
class Http
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@options = {cache: nil}.merge options
|
13
|
+
if @options[:cache]
|
14
|
+
cache_options = @options[:cache].merge({
|
15
|
+
host: "127.0.0.1",
|
16
|
+
port: "6379"
|
17
|
+
})
|
18
|
+
if cache_options.has_key?(:url)
|
19
|
+
url = cache_options[:url]
|
20
|
+
uri = URI.parse(url)
|
21
|
+
#puts "Connecting to redis with url #{url}..."
|
22
|
+
@cache = Redis.new(host: uri.host, port: uri.port, password: uri.password)
|
23
|
+
elsif host != nil && port != nil
|
24
|
+
#puts "Connecting to redis on host #{host} at port #{port}..."
|
25
|
+
@cache = Redis.new(host: cache_options[:host], port: cache_options[:port])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def get(url, params = {})
|
31
|
+
if @cache && (!@options[:cache].has_key?(:invalidate) || !@options[:cache][:invalidate])
|
32
|
+
key = get_key(url)
|
33
|
+
data = @cache.get(key)
|
34
|
+
if data
|
35
|
+
#puts 'Read from cache... ' + url
|
36
|
+
return data
|
37
|
+
end
|
38
|
+
end
|
39
|
+
if params.keys.count > 0
|
40
|
+
query_string = URI.encode_www_form(params)
|
41
|
+
url = url + "?" + query_string
|
42
|
+
end
|
43
|
+
#puts 'Get url... ' + url
|
44
|
+
resp = Net::HTTP.get_response(URI.parse(url))
|
45
|
+
data = resp.body
|
46
|
+
if data
|
47
|
+
if @cache
|
48
|
+
#puts 'Write to cache... ' + url
|
49
|
+
key = get_key(url)
|
50
|
+
@cache.set(key, data)
|
51
|
+
if @options[:cache] && @options[:cache].has_key?(:expire)
|
52
|
+
@cache.expire(key, @options[:cache][:expire])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return data
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_json(url, params = {})
|
60
|
+
data = get(url, params)
|
61
|
+
if data != nil
|
62
|
+
return JSON.parse(data)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_dom(url, params = {})
|
67
|
+
data = get(url, params)
|
68
|
+
if data != nil
|
69
|
+
return REXML::Document.new(data)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
private
|
75
|
+
def get_key(url)
|
76
|
+
"Forecast::Http::" + url
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
forecast:
|
2
|
+
synonyms:
|
3
|
+
-
|
4
|
+
- 'Clear'
|
5
|
+
- 'Sunny'
|
6
|
+
- 'Sunshine'
|
7
|
+
- 'No Clouds'
|
8
|
+
- 'Fair'
|
9
|
+
- 'Breezy'
|
10
|
+
-
|
11
|
+
- 'Light Rain'
|
12
|
+
- 'Drizzle'
|
13
|
+
- 'Light showers'
|
14
|
+
-
|
15
|
+
- 'Rain'
|
16
|
+
- 'Showers'
|
17
|
+
-
|
18
|
+
- 'Heavy Rain'
|
19
|
+
- 'Thundershowers'
|
20
|
+
-
|
21
|
+
- 'Partly Cloudy'
|
22
|
+
- 'Clouds Sun'
|
23
|
+
- 'Fog Sun'
|
24
|
+
- 'Few Clouds'
|
25
|
+
-
|
26
|
+
- 'Overcast'
|
27
|
+
- 'Cloudy'
|
28
|
+
- 'Clouds'
|
29
|
+
-
|
30
|
+
- 'Storm'
|
31
|
+
- 'Thunderstorm'
|
32
|
+
- 'Blizzard'
|
@@ -1,10 +1,12 @@
|
|
1
1
|
forecast:
|
2
2
|
themes:
|
3
|
-
weather_icons:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
weather_icons:
|
4
|
+
prefix: 'wi wi-'
|
5
|
+
conditions:
|
6
|
+
Clear: "day-sunny"
|
7
|
+
Partly Cloudy: "sunny-overcast"
|
8
|
+
Cloudy: "day-cloudy"
|
9
|
+
Mostly Cloudy: "cloudy"
|
10
|
+
Light Rain: "showers"
|
11
|
+
Rain: "rain"
|
12
|
+
Heavy Rain: "rain"
|
data/lib/forecast/utils.rb
CHANGED
@@ -7,9 +7,50 @@ class Forecast
|
|
7
7
|
module Utils
|
8
8
|
class << self
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
|
11
|
+
def underscore(string)
|
12
|
+
if string.is_a?(String)
|
13
|
+
return string.gsub(/::/, '/').
|
14
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
15
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
16
|
+
tr("-", "_").
|
17
|
+
downcase
|
18
|
+
elsif string.is_a?(Hash)
|
19
|
+
return Hash[string.map { |k, v| [Forecast::Utils.underscore(k.to_s).to_sym, v.is_a?(Hash) ? Forecast::Utils.underscore(v) : v] }]
|
20
|
+
else
|
21
|
+
string
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def fahrenheit_to_kelvin(fahrenheit)
|
26
|
+
((fahrenheit - 32) / 1.8) - 273.15
|
27
|
+
end
|
28
|
+
|
29
|
+
def fahrenheit_to_celsius(fahrenheit)
|
30
|
+
((fahrenheit - 32) / 1.8)
|
31
|
+
end
|
32
|
+
|
33
|
+
def kelvin_to_fahrenheit(kelvin)
|
34
|
+
return ((kelvin - 273.15) * 1.8 + 32)
|
35
|
+
end
|
36
|
+
|
37
|
+
def kelvin_to_celsius(kelvin)
|
38
|
+
kelvin - 273.15
|
39
|
+
end
|
40
|
+
|
41
|
+
def celsius_to_fahrenheit(celsius)
|
42
|
+
celsius * 1.8 + 32
|
43
|
+
end
|
44
|
+
|
45
|
+
def celsius_to_kelvin(celsius)
|
46
|
+
celsius + 273.15
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_json(url, params = {})
|
50
|
+
if params.keys.count > 0
|
51
|
+
query_string = URI.encode_www_form(params)
|
52
|
+
url = url + "?" + query_string
|
53
|
+
end
|
13
54
|
resp = Net::HTTP.get_response(URI.parse(url))
|
14
55
|
data = resp.body
|
15
56
|
result = JSON.parse(data)
|
@@ -19,14 +60,68 @@ class Forecast
|
|
19
60
|
return nil
|
20
61
|
end
|
21
62
|
|
22
|
-
def get_doc(url, params)
|
23
|
-
|
24
|
-
|
63
|
+
def get_doc(url, params = {})
|
64
|
+
if params.keys.count > 0
|
65
|
+
query_string = URI.encode_www_form(params)
|
66
|
+
url = url + "?" + query_string
|
67
|
+
end
|
25
68
|
xml_data = Net::HTTP.get_response(URI.parse(url)).body
|
26
69
|
doc = REXML::Document.new(xml_data)
|
27
70
|
return doc
|
28
71
|
end
|
29
72
|
|
73
|
+
def word_similarity(first, second)
|
74
|
+
|
75
|
+
if !first.is_a?(String) || !second.is_a?(String)
|
76
|
+
return 0
|
77
|
+
end
|
78
|
+
similar_words = 0.0
|
79
|
+
first_words = first.downcase.split(/\W+/)
|
80
|
+
second_words = second.downcase.split(/\W+/)
|
81
|
+
|
82
|
+
first_words.each do |first_word|
|
83
|
+
second_words.each do |second_word|
|
84
|
+
similar = 0.0
|
85
|
+
if first_word == second_word
|
86
|
+
similar = 1.0
|
87
|
+
else
|
88
|
+
l1 = levenshtein(first_word, second_word)
|
89
|
+
l = 1 - (l1.to_f / ([first_word.length, second_word.length].max))
|
90
|
+
l = [0, similar].max
|
91
|
+
l = [similar, 1].min
|
92
|
+
if l1 > 0.6
|
93
|
+
similar = 0.1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
similar_words+= similar
|
97
|
+
end
|
98
|
+
end
|
99
|
+
count = first_words.concat(second_words).uniq.length
|
100
|
+
similarity = similar_words / count
|
101
|
+
return similarity
|
102
|
+
end
|
103
|
+
|
104
|
+
def levenshtein(first, second)
|
105
|
+
matrix = [(0..first.length).to_a]
|
106
|
+
(1..second.length).each do |j|
|
107
|
+
matrix << [j] + [0] * (first.length)
|
108
|
+
end
|
109
|
+
(1..second.length).each do |i|
|
110
|
+
(1..first.length).each do |j|
|
111
|
+
if first[j-1] == second[i-1]
|
112
|
+
matrix[i][j] = matrix[i-1][j-1]
|
113
|
+
else
|
114
|
+
matrix[i][j] = [
|
115
|
+
matrix[i-1][j],
|
116
|
+
matrix[i][j-1],
|
117
|
+
matrix[i-1][j-1],
|
118
|
+
].min + 1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
return matrix.last.last
|
123
|
+
end
|
124
|
+
|
30
125
|
end
|
31
126
|
end
|
32
127
|
end
|
data/lib/forecast/version.rb
CHANGED
data/lib/forecast.rb
CHANGED
@@ -1,141 +1,73 @@
|
|
1
|
+
require 'ostruct'
|
1
2
|
require "forecast/version"
|
2
3
|
require "forecast/config"
|
3
|
-
require "forecast/
|
4
|
+
require "forecast/utils"
|
4
5
|
require "forecast/collection"
|
5
6
|
require "forecast/adapter"
|
6
7
|
require "forecast/adapters/yahoo_adapter"
|
7
8
|
require "forecast/adapters/open_weather_map_adapter"
|
8
9
|
require "forecast/adapters/wunderground_adapter"
|
9
|
-
require "
|
10
|
-
require "
|
10
|
+
require "forecast/adapters/forecast_io_adapter"
|
11
|
+
require "forecast/http"
|
11
12
|
|
12
13
|
class Forecast
|
13
14
|
|
14
|
-
|
15
|
+
PROVIDERS = Dir.glob(File.expand_path(File.dirname(__FILE__) + '/forecast/adapters/*.*')).map{ |f| File.basename(f, '_adapter.rb') };
|
15
16
|
|
16
|
-
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
@source.send(method, *args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(attrs = {})
|
22
|
+
@source = OpenStruct.new(attrs)
|
23
|
+
end
|
17
24
|
|
18
|
-
|
25
|
+
def as_json(options = nil)
|
26
|
+
@source.table.as_json(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_json *a
|
30
|
+
self.marshal_dump.to_json a
|
31
|
+
end
|
32
|
+
|
33
|
+
def icon
|
34
|
+
# Pick icon from theme
|
35
|
+
if self.condition != nil && Forecast.config.theme.is_a?(Hash)
|
36
|
+
icon_prefix = Forecast.config.theme.has_key?('prefix') ? Forecast.config.theme['prefix'] : ''
|
37
|
+
icon_suffix = Forecast.config.theme.has_key?('suffix') ? Forecast.config.theme['suffix'] : ''
|
38
|
+
icon_name = Forecast.config.theme['conditions'].has_key?(self.condition) ? Forecast.config.theme['conditions'][self.condition] : self.condition
|
39
|
+
# Dasherize
|
40
|
+
icon_name = icon_name.to_s.gsub(/(.)([A-Z])/,'\1-\2').gsub(/\s*/, '').downcase
|
41
|
+
icon = icon_prefix + icon_name + icon_suffix
|
42
|
+
return icon != nil ? icon : self.icon
|
43
|
+
end
|
44
|
+
# Slugified condition as icon name
|
45
|
+
self.condition.is_a?(String) && self.condition.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
|
46
|
+
end
|
19
47
|
|
20
48
|
# class
|
21
49
|
class << self
|
22
50
|
|
23
51
|
def current(latitude, longitude)
|
24
|
-
|
25
|
-
forecast = read_cache(cache_key)
|
26
|
-
if forecast == nil
|
27
|
-
forecast = adapter.current(latitude, longitude)
|
28
|
-
write_cache(cache_key, forecast)
|
29
|
-
end
|
30
|
-
return forecast
|
52
|
+
return adapter.current(latitude, longitude)
|
31
53
|
end
|
32
54
|
|
33
55
|
def hourly(latitude, longitude)
|
34
|
-
|
35
|
-
forecasts = read_cache(cache_key)
|
36
|
-
if forecasts == nil
|
37
|
-
forecasts = adapter.hourly(latitude, longitude)
|
38
|
-
write_cache(cache_key, forecasts)
|
39
|
-
end
|
40
|
-
return forecasts
|
56
|
+
return adapter.hourly(latitude, longitude)
|
41
57
|
end
|
42
58
|
|
43
59
|
def daily(latitude, longitude)
|
44
|
-
|
45
|
-
forecasts = read_cache(cache_key)
|
46
|
-
if forecasts == nil
|
47
|
-
forecasts = adapter.daily(latitude, longitude)
|
48
|
-
write_cache(cache_key, forecasts)
|
49
|
-
end
|
50
|
-
return forecasts
|
60
|
+
return adapter.daily(latitude, longitude)
|
51
61
|
end
|
52
62
|
|
53
|
-
private
|
54
|
-
|
55
|
-
@adapter = nil
|
56
|
-
|
63
|
+
private
|
64
|
+
|
57
65
|
def adapter
|
58
66
|
if @adapter == nil
|
59
67
|
@adapter = Forecast::Adapter.instance
|
60
68
|
end
|
61
69
|
return @adapter
|
62
70
|
end
|
63
|
-
|
64
|
-
|
65
|
-
@cache = nil
|
66
|
-
|
67
|
-
def cache
|
68
|
-
cache = Forecast.config.cache
|
69
|
-
if @cache == nil && ( cache != nil || (!!cache == cache) && cache == true )
|
70
|
-
if !!cache == cache
|
71
|
-
Forecast.config.cache = {
|
72
|
-
expire: 5,
|
73
|
-
prefix: :forecast,
|
74
|
-
host: "127.0.0.1",
|
75
|
-
port: "6379",
|
76
|
-
url: nil
|
77
|
-
}
|
78
|
-
end
|
79
|
-
cache_config = Forecast.config.cache
|
80
|
-
begin
|
81
|
-
if cache_config['url'] != nil
|
82
|
-
redis_url = cache_config['url']
|
83
|
-
uri = URI.parse(redis_url)
|
84
|
-
@cache = Redis.new(host: uri.host, port: uri.port, password: uri.password)
|
85
|
-
else
|
86
|
-
@cache = Redis.new(host: cache_config['host'], port: cache_config['port'])
|
87
|
-
end
|
88
|
-
@cache.ping
|
89
|
-
rescue
|
90
|
-
puts "error connecting to redis"
|
91
|
-
end
|
92
|
-
end
|
93
|
-
return @cache
|
94
|
-
end
|
95
|
-
|
96
|
-
def cache_key(key)
|
97
|
-
cache_prefix = Forecast.config.cache[:prefix]
|
98
|
-
return "#{cache_prefix.to_s}:#{key}"
|
99
|
-
end
|
100
|
-
|
101
|
-
def cache_expire
|
102
|
-
cache_expire = Forecast.config.cache[:expire]
|
103
|
-
end
|
104
|
-
|
105
|
-
def write_cache(key, data)
|
106
|
-
if cache == nil
|
107
|
-
return;
|
108
|
-
end
|
109
|
-
puts "WRITE TO CACHE... " + cache_key(key).to_s + ", cache_expire: " + cache_expire.to_s
|
110
|
-
cache.set(cache_key(key), data.to_json)
|
111
|
-
cache.expire(cache_key(key), cache_expire)
|
112
|
-
end
|
113
|
-
|
114
|
-
def read_cache(key)
|
115
|
-
if cache == nil
|
116
|
-
return nil;
|
117
|
-
end
|
118
|
-
cached_result = cache.get(cache_key(key))
|
119
|
-
result = nil
|
120
|
-
if cached_result != nil
|
121
|
-
puts "READ FROM CACHE: " + cache_key(key).to_s + ", cache_expire: " + cache_expire.to_s
|
122
|
-
json = JSON.parse(cached_result)
|
123
|
-
if json.is_a?(Array)
|
124
|
-
result = Forecast::Collection.new
|
125
|
-
json.each do |obj|
|
126
|
-
forecast = Forecast.new
|
127
|
-
forecast.from_json(obj)
|
128
|
-
result << forecast
|
129
|
-
end
|
130
|
-
elsif json.is_a?(Object)
|
131
|
-
result = Forecast.new
|
132
|
-
result.from_json(json)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
return result
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
71
|
|
140
72
|
end
|
141
73
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
New York:
|
2
|
+
latitude: 41.145495
|
3
|
+
longitude: -73.994901
|
4
|
+
Miami:
|
5
|
+
latitude: 25.775278
|
6
|
+
longitude: -80.208889
|
7
|
+
San Francisco:
|
8
|
+
latitude: 37.783333
|
9
|
+
longitude: -122.416667
|
10
|
+
London:
|
11
|
+
latitude: 51.50939
|
12
|
+
longitude: -0.11832
|
13
|
+
Johannesburg:
|
14
|
+
latitude: -26.204444
|
15
|
+
longitude: 28.045556
|
16
|
+
Sidney:
|
17
|
+
latitude: -33.865
|
18
|
+
longitude: 151.209444
|
19
|
+
Hamburg:
|
20
|
+
latitude: 53.55075
|
21
|
+
longitude: 9.93026
|