Module: ForecastIo::Utils
- Included in:
- Lita::Handlers::OnewheelForecastIo
- Defined in:
- lib/lita/handlers/utils.rb
Constant Summary collapse
- REDIS_KEY =
'forecast_io'
Instance Method Summary collapse
-
#ansi_wind_arrows ⇒ Object
This is a little weird, because the arrows are 180° rotated.
- #ascii_wind_arrows ⇒ Object
- #celcius(degrees_c) ⇒ Object
- #check_and_set_scale(key, user_requested_scale) ⇒ Object
-
#collect_values(hashes) ⇒ Object
this method is simply to transform an array of hashes into a hash of arrays kudos to Phrogz for the info here: stackoverflow.com/questions/5490952/merge-array-of-hashes-to-get-hash-of-arrays-of-values.
-
#condense_data(data, limit) ⇒ Object
this method lets us condense rain forcasts into smaller sets it averages the values contained in a chunk of data perportionate the the limit set then returns a new array of hashes containing those averaged values.
- #determine_time_offset(data_offset) ⇒ Object
- #fahrenheit(degrees_c) ⇒ Object
- #fix_time(unixtime, data_offset) ⇒ Object
- #forecast_text(forecast) ⇒ Object
-
#geo_lookup(user, query, persist = true) ⇒ Object
Perform a geocoder lookup based on a) the query or b) the user’s serialized state.
- #get_accumulation(accum_mm) ⇒ Object
- #get_cardinal_direction_from_bearing(bearing) ⇒ Object
- #get_chance_of(rain_or_snow, currently) ⇒ Object
-
#get_colored_string(data_limited, key, dot_str, range_hash) ⇒ Object
get_colored_string Returns the dot_str colored based on our range_hash.
- #get_distance(distance_metric, scale) ⇒ Object
-
#get_dot(probability, char_array) ⇒ Object
°℃℉.
- #get_dot_str(chars, data, min, differential, key) ⇒ Object
- #get_eightball_response(chance) ⇒ Object
-
#get_forecast_io_results(user, location, time = nil) ⇒ Object
Time should be in the format specified here (subset of 8601) developer.forecast.io/docs/v2#time_call.
- #get_humidity(humidity_decimal) ⇒ Object
-
#get_other_scale(scale) ⇒ Object
A bit optimistic, but I really like the Cs.
- #get_percentage(number, differential, min) ⇒ Object
- #get_scale(user) ⇒ Object
- #get_speed(speed_imperial) ⇒ Object
- #get_temperature(temp_c) ⇒ Object
-
#gimme_some_weather(url) ⇒ Object
Wrapped for testing.
- #handle_geo_lookup(response) ⇒ Object
- #inches_from_mm(dist_mm) ⇒ Object
-
#is_it_raining(response) ⇒ Object
Return an eightball response based on the current chance of rain.
-
#is_it_snowing(response) ⇒ Object
Return an eightball response based on the current chance of snow.
- #kelvin(degrees_c) ⇒ Object
- #kilometers(miles) ⇒ Object
- #miles(kilometers) ⇒ Object
-
#optimistic_geo_wrapper(query, geocoder_key) ⇒ Object
Geographical stuffs Now with moar caching!.
- #set_scale(user) ⇒ Object
Instance Method Details
#ansi_wind_arrows ⇒ Object
This is a little weird, because the arrows are 180° rotated. That’s because the wind bearing is “out of the N” not “towards the N”.
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 |
# File 'lib/lita/handlers/utils.rb', line 463 def ansi_wind_arrows case robot.config.robot.adapter when :slack {'N' => ':arrow_down:', 'NE' => ':arrow_lower_left:', 'E' => ':arrow_left:', 'SE' => ':arrow_upper_left:', 'S' => ':arrow_up:', 'SW' => ':arrow_upper_right:', 'W' => ':arrow_right:', 'NW' => ':arrow_lower_right:' } else {'N' => '↓', 'NE' => '↙', 'E' => '←', 'SE' => '↖', 'S' => '↑', 'SW' => '↗', 'W' => '→', 'NW' => '↘' } end end |
#ascii_wind_arrows ⇒ Object
488 489 490 491 492 493 494 495 496 497 498 |
# File 'lib/lita/handlers/utils.rb', line 488 def ascii_wind_arrows { 'N' => 'v', 'NE' => ',', 'E' => '<', 'SE' => "\\", 'S' => '^', 'SW' => '/', 'W' => '>', 'NW' => '.' } end |
#celcius(degrees_c) ⇒ Object
413 414 415 416 |
# File 'lib/lita/handlers/utils.rb', line 413 def celcius(degrees_c) #(0.5555555556 * (degrees_c.to_f - 32)).round(2) degrees_c.to_f.round(2) end |
#check_and_set_scale(key, user_requested_scale) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/lita/handlers/utils.rb', line 200 def check_and_set_scale(key, user_requested_scale) persisted_scale = redis.hget(REDIS_KEY, key) if %w(c f k).include? user_requested_scale scale_to_set = user_requested_scale else # Toggle mode scale_to_set = get_other_scale(persisted_scale) end if persisted_scale == scale_to_set reply = "Scale is already set to #{scale_to_set}!" else redis.hset(REDIS_KEY, key, scale_to_set) reply = "Scale set to #{scale_to_set}" end reply end |
#collect_values(hashes) ⇒ Object
this method is simply to transform an array of hashes into a hash of arrays kudos to Phrogz for the info here: stackoverflow.com/questions/5490952/merge-array-of-hashes-to-get-hash-of-arrays-of-values
330 331 332 |
# File 'lib/lita/handlers/utils.rb', line 330 def collect_values(hashes) {}.tap{ |r| hashes.each{ |h| h.each{ |k,v| (r[k]||=[]) << v } } } end |
#condense_data(data, limit) ⇒ Object
this method lets us condense rain forcasts into smaller sets it averages the values contained in a chunk of data perportionate the the limit set then returns a new array of hashes containing those averaged values
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/lita/handlers/utils.rb', line 308 def condense_data(data, limit) return if limit >= data.length chunk_length = (data.length / limit.to_f).round results = [] data.each_slice(chunk_length) do |chunk| chunk_results = {} condensed_chunk = collect_values(chunk) condensed_chunk.each do |k, v| if v[0].class == Fixnum || v[0].class == Float new_val = v.inject{ |sum,val| sum + val} / v.size elsif v[0].class == String new_val = v[0] end chunk_results[k] = new_val end results << chunk_results end results end |
#determine_time_offset(data_offset) ⇒ Object
261 262 263 264 265 |
# File 'lib/lita/handlers/utils.rb', line 261 def determine_time_offset(data_offset) system_offset_seconds = Time.now.utc_offset data_offset_seconds = data_offset * 60 * 60 system_offset_seconds - data_offset_seconds end |
#fahrenheit(degrees_c) ⇒ Object
423 424 425 |
# File 'lib/lita/handlers/utils.rb', line 423 def fahrenheit(degrees_c) ((degrees_c.to_f * 9/5) + 32).round(2) end |
#fix_time(unixtime, data_offset) ⇒ Object
257 258 259 |
# File 'lib/lita/handlers/utils.rb', line 257 def fix_time(unixtime, data_offset) unixtime - determine_time_offset(data_offset) end |
#forecast_text(forecast) ⇒ Object
245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/lita/handlers/utils.rb', line 245 def forecast_text(forecast) forecast_str = "weather is currently #{get_temperature forecast['currently']['temperature']} " + "and #{forecast['currently']['summary'].downcase}. Winds out of the #{get_cardinal_direction_from_bearing forecast['currently']['windBearing']} at #{get_speed(forecast['currently']['windSpeed'])}. " if forecast['minutely'] minute_forecast = forecast['minutely']['summary'].to_s.downcase.chop forecast_str += "It will be #{minute_forecast}, and #{forecast['hourly']['summary'].to_s.downcase.chop}. " end forecast_str += "There are also #{forecast['currently']['ozone'].to_s} ozones." end |
#geo_lookup(user, query, persist = true) ⇒ Object
Perform a geocoder lookup based on a) the query or b) the user’s serialized state. If neither of those exist, default to config location.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/lita/handlers/utils.rb', line 64 def geo_lookup(user, query, persist = true) Lita.logger.debug "Performing geolookup for '#{user}' for '#{query}'" geocoded = nil if query.nil? or query.empty? Lita.logger.debug "No query specified, pulling from redis '#{REDIS_KEY}', '#{user}'" serialized_geocoded = redis.hget(REDIS_KEY, user) unless serialized_geocoded == 'null' or serialized_geocoded.nil? if serialized_geocoded[/^http/] query = serialized_geocoded else geocoded = JSON.parse(serialized_geocoded) end Lita.logger.debug "Cached location: #{geocoded.inspect}" end end query = (query.nil?)? config.default_location : query Lita.logger.debug "q & g #{query.inspect} #{geocoded.inspect}" if query[/^http/] or (!geocoded.nil? and geocoded.key? 'geo') # For now this is aaronpk's loc Lita.logger.debug "Getting location from #{query}" resp = JSON.parse(RestClient.get query) locality = '' if resp['geo'] locality = resp['geo']['locality'] end geocoded = optimistic_geo_wrapper locality, config.geocoder_key # loc = Location.new( # locality, # resp['location']['latitude'], # resp['location']['longitude'] # ) if persist redis.hset(REDIS_KEY, user, query) end else unless geocoded # uri = "https://atlas.p3k.io/api/geocode?input=#{URI.escape query}" # Lita.logger.debug "Redis hget failed, performing lookup for #{query} on #{uri}" geocoded = optimistic_geo_wrapper query, config.geocoder_key # Catch network errors here # begin # geocoded = JSON.parse RestClient.get(uri) # rescue RuntimeError => e # puts "x" # end Lita.logger.debug "Geolocation found. '#{geocoded.inspect}' failed, performing lookup" if persist redis.hset(REDIS_KEY, user, geocoded.to_json) end end # {"latitude": 45.51179, # "longitude": -122.67563, # "locality": "Portland", # "region": "Oregon", # "country": "USA", # "best_name": "Portland", # "full_name": "Portland, Oregon, USA", # "postal-code": "97201", # "timezone": "America\/Los_Angeles", # "offset": "-07:00", # "seconds": -25200, # "localtime": "2018-08-09T08:05:43-07:00"} # loc = Location.new( # geocoded['best_name'], # geocoded['latitude'], # geocoded['longitude'] # ) # loc = Location.new( # geocoded['formatted_address'], # geocoded['geometry']['location']['lat'], # geocoded['geometry']['location']['lng'] # ) end Lita.logger.debug "best_name: #{geocoded['best_name']}" Lita.logger.debug "display_name: #{geocoded['display_name']}" Lita.logger.debug "formatted_address: #{geocoded['formatted_address']}" if geocoded['best_name'] loc = Location.new( geocoded['best_name'], geocoded['latitude'], geocoded['longitude']) elsif geocoded['lon'] loc = Location.new( "#{geocoded['address']['city']}, #{geocoded['address']['state']}", geocoded['lat'], geocoded['lon']) else loc = Location.new( geocoded['formatted_address'], geocoded['geometry']['location']['lat'], geocoded['geometry']['location']['lng']) end Lita.logger.debug "geocoded: '#{geocoded}'" Lita.logger.debug "loc: '#{loc}'" loc end |
#get_accumulation(accum_mm) ⇒ Object
401 402 403 404 405 406 407 |
# File 'lib/lita/handlers/utils.rb', line 401 def get_accumulation(accum_mm) if @scale == 'c' or @scale == 'k' accum_mm.round(0).to_s + 'mm' else inches_from_mm(accum_mm).to_s + 'in' end end |
#get_cardinal_direction_from_bearing(bearing) ⇒ Object
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
# File 'lib/lita/handlers/utils.rb', line 439 def get_cardinal_direction_from_bearing(bearing) case bearing when 0..25 'N' when 26..65 'NE' when 66..115 'E' when 116..155 'SE' when 156..205 'S' when 206..245 'SW' when 246..295 'W' when 296..335 'NW' when 336..360 'N' end end |
#get_chance_of(rain_or_snow, currently) ⇒ Object
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/lita/handlers/utils.rb', line 35 def get_chance_of(rain_or_snow, currently) # This is a fallthrough so we'll reply no to rain if it's snowing, and vice versa. chance = 0 if currently['precipType'] == rain_or_snow # If we match the specified string ['rain', 'snow'] chance = currently['precipProbability'] # Set the probability for 8-ball reckoning. end chance # Probably superfluous. end |
#get_colored_string(data_limited, key, dot_str, range_hash) ⇒ Object
get_colored_string Returns the dot_str colored based on our range_hash. range_hash is one of our color hashes, e.g. get_wind_range_colors key is used to index each element in data_limited to get our value to compare with the range_hash.
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/lita/handlers/utils.rb', line 275 def get_colored_string(data_limited, key, dot_str, range_hash) color = nil prev_color = nil collect_str = '' colored_str = '' data_limited.each_with_index do |data, index| range_hash.keys.each do |range_hash_key| if range_hash_key.cover? data[key] # Super secred cover sauce color = range_hash[range_hash_key] if index == 0 prev_color = color end end end # If the color changed, let's update the collect_str unless color == prev_color colored_str += "\x03" + colors[prev_color] + collect_str collect_str = '' end collect_str += dot_str[index] prev_color = color end # And get the last one. colored_str += "\x03" + colors[color] + collect_str + "\x03" end |
#get_distance(distance_metric, scale) ⇒ Object
393 394 395 396 397 398 399 |
# File 'lib/lita/handlers/utils.rb', line 393 def get_distance(distance_metric, scale) if scale == 'f' miles(distance_metric).to_s + ' mi' else distance_metric.to_s + ' km' end end |
#get_dot(probability, char_array) ⇒ Object
°℃℉
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/lita/handlers/utils.rb', line 353 def get_dot(probability, char_array) if probability < 0 or probability > 1 Lita.logger.error "get_dot Probably a probability problem: #{probability} should be between 0 and 1." return '?' end if probability == 0 return char_array[0] elsif probability <= 0.10 return char_array[1] elsif probability <= 0.25 return char_array[2] elsif probability <= 0.50 return char_array[3] elsif probability <= 0.75 return char_array[4] elsif probability <= 1.00 return char_array[5] end end |
#get_dot_str(chars, data, min, differential, key) ⇒ Object
334 335 336 337 338 339 340 341 |
# File 'lib/lita/handlers/utils.rb', line 334 def get_dot_str(chars, data, min, differential, key) str = '' data.each do |datum| percentage = get_percentage(datum[key], differential, min) str += get_dot(percentage, chars) end str end |
#get_eightball_response(chance) ⇒ Object
24 25 26 27 28 29 30 31 32 33 |
# File 'lib/lita/handlers/utils.rb', line 24 def get_eightball_response(chance) case chance when 0..0.2 MagicEightball.reply :no when 0.201..0.7 MagicEightball.reply :maybe when 0.701..1 MagicEightball.reply :yes end end |
#get_forecast_io_results(user, location, time = nil) ⇒ Object
Time should be in the format specified here (subset of 8601) developer.forecast.io/docs/v2#time_call
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/lita/handlers/utils.rb', line 223 def get_forecast_io_results(user, location, time = nil) if ! config.api_uri or ! config.api_key Lita.logger.error "Configuration missing! '#{config.api_uri}' '#{config.api_key}'" raise StandardError.new('Configuration missing!') end uri = config.api_uri + config.api_key + '/' + "#{location.latitude},#{location.longitude}" if time uri += ",#{time}" end uri += "?units=si" Lita.logger.debug "Requesting forcast data from: #{uri}" set_scale(user) gimme_some_weather uri end |
#get_humidity(humidity_decimal) ⇒ Object
409 410 411 |
# File 'lib/lita/handlers/utils.rb', line 409 def get_humidity(humidity_decimal) (humidity_decimal * 100).round(0).to_s + '%' end |
#get_other_scale(scale) ⇒ Object
A bit optimistic, but I really like the Cs.
501 502 503 504 505 506 507 |
# File 'lib/lita/handlers/utils.rb', line 501 def get_other_scale(scale) if scale.downcase == 'c' 'f' else 'c' end end |
#get_percentage(number, differential, min) ⇒ Object
343 344 345 346 347 348 349 350 |
# File 'lib/lita/handlers/utils.rb', line 343 def get_percentage(number, differential, min) if differential == 0 percentage = number else percentage = (number.to_f - min) / (differential) end percentage end |
#get_scale(user) ⇒ Object
191 192 193 194 195 196 197 198 |
# File 'lib/lita/handlers/utils.rb', line 191 def get_scale(user) key = user.name + '-scale' scale = redis.hget(REDIS_KEY, key) if scale.nil? scale = 'f' end scale end |
#get_speed(speed_imperial) ⇒ Object
385 386 387 388 389 390 391 |
# File 'lib/lita/handlers/utils.rb', line 385 def get_speed(speed_imperial) if @scale == 'c' kilometers(speed_imperial).to_s + ' kph' else speed_imperial.to_s + ' mph' end end |
#get_temperature(temp_c) ⇒ Object
374 375 376 377 378 379 380 381 382 383 |
# File 'lib/lita/handlers/utils.rb', line 374 def get_temperature(temp_c) if @scale == 'c' #celcius(temp_c).to_s + '°C' temp_c.to_s + '°C' elsif @scale == 'k' kelvin(temp_c).to_s + 'K' else fahrenheit(temp_c).to_s + '°F' end end |
#gimme_some_weather(url) ⇒ Object
Wrapped for testing.
178 179 180 181 182 |
# File 'lib/lita/handlers/utils.rb', line 178 def gimme_some_weather(url) # HTTParty.get url response = RestClient.get(url) JSON.parse(response.to_str) end |
#handle_geo_lookup(response) ⇒ Object
240 241 242 243 |
# File 'lib/lita/handlers/utils.rb', line 240 def handle_geo_lookup(response) location = geo_lookup(response.user, response.match_data[1], persist = false) response.reply "#{location.latitude}, #{location.longitude}" end |
#inches_from_mm(dist_mm) ⇒ Object
427 428 429 |
# File 'lib/lita/handlers/utils.rb', line 427 def inches_from_mm(dist_mm) (dist_mm * 0.0393701).round(1) end |
#is_it_raining(response) ⇒ Object
Return an eightball response based on the current chance of rain. If it’s snowing, it’s a hard no.
8 9 10 11 12 13 |
# File 'lib/lita/handlers/utils.rb', line 8 def is_it_raining(response) geocoded = geo_lookup response.user, response.match_data[1] forecast = get_forecast_io_results response.user, geocoded response.reply get_eightball_response get_chance_of('rain', forecast['currently']) end |
#is_it_snowing(response) ⇒ Object
Return an eightball response based on the current chance of snow. If it’s raining, it’s a hard no.
17 18 19 20 21 22 |
# File 'lib/lita/handlers/utils.rb', line 17 def is_it_snowing(response) geocoded = geo_lookup response.user, response.match_data[1] forecast = get_forecast_io_results response.user, geocoded response.reply get_eightball_response get_chance_of('snow', forecast['currently']) end |
#kelvin(degrees_c) ⇒ Object
418 419 420 421 |
# File 'lib/lita/handlers/utils.rb', line 418 def kelvin(degrees_c) #((degrees_c.to_f + 459.67) * 5/9).round(2) (degrees_c.to_f + 459.67).round(2) end |
#kilometers(miles) ⇒ Object
431 432 433 |
# File 'lib/lita/handlers/utils.rb', line 431 def kilometers(miles) (miles * 1.6).round(2) end |
#miles(kilometers) ⇒ Object
435 436 437 |
# File 'lib/lita/handlers/utils.rb', line 435 def miles(kilometers) (kilometers / 1.6).round(2) end |
#optimistic_geo_wrapper(query, geocoder_key) ⇒ Object
Geographical stuffs Now with moar caching!
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/lita/handlers/utils.rb', line 48 def optimistic_geo_wrapper(query, geocoder_key) Lita.logger.debug "Optimistically geo wrapping #{query}!" ::Geocoder.configure( :api_key => geocoder_key ) geocoded = nil result = ::Geocoder.search(query) Lita.logger.debug "Geocoder result: '#{result.inspect}'" if result[0] geocoded = result[0].data end geocoded end |
#set_scale(user) ⇒ Object
184 185 186 187 188 189 |
# File 'lib/lita/handlers/utils.rb', line 184 def set_scale(user) key = user.name + '-scale' if scale = redis.hget(REDIS_KEY, key) @scale = scale end end |