module ForecastIo::Utils

Constants

REDIS_KEY

Public Instance Methods

ansi_wind_arrows() click to toggle source

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”.

# 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() click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source

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

# 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) click to toggle source

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

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# File lib/lita/handlers/utils.rb, line 257
def fix_time(unixtime, data_offset)
  unixtime - determine_time_offset(data_offset)
end
forecast_text(forecast) click to toggle source
# 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) click to toggle source

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.

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source

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.

# 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) click to toggle source
# 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) click to toggle source

°℃℉

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source

Time should be in the format specified here (subset of 8601) developer.forecast.io/docs/v2#time_call

# 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) click to toggle source
# 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) click to toggle source

A bit optimistic, but I really like the Cs.

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source

Wrapped for testing.

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source

Return an eightball response based on the current chance of rain. If it's snowing, it's a hard no.

# 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) click to toggle source

Return an eightball response based on the current chance of snow. If it's raining, it's a hard no.

# 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) click to toggle source
# 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) click to toggle source
# File lib/lita/handlers/utils.rb, line 431
def kilometers(miles)
  (miles * 1.6).round(2)
end
miles(kilometers) click to toggle source
# File lib/lita/handlers/utils.rb, line 435
def miles(kilometers)
  (kilometers / 1.6).round(2)
end
optimistic_geo_wrapper(query, geocoder_key) click to toggle source

Geographical stuffs Now with moar caching!

# 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) click to toggle source
# 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