diff --git a/2A5C0A87-204E-49EA-94A7-8E62BB4EFD8A.png b/2A5C0A87-204E-49EA-94A7-8E62BB4EFD8A.png new file mode 100644 index 0000000..3c02bab Binary files /dev/null and b/2A5C0A87-204E-49EA-94A7-8E62BB4EFD8A.png differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c3c43ce --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# Forecast Workflow for Alfred + +![screenshot][screenshot] + +[screenshot]: http://i.imgur.com/enspDWu.png + +# Requirements + +- [Alfred](http://www.alfredapp.com/) +- [Alfred Powerpack](http://www.alfredapp.com/powerpack/) +- OS X Mavericks + +# Installation + +Install the workflow. Edit the script filter to add your location and API keys: + +- FORECAST_API_KEY: Get an API key [here][forecast-api-key]. +- GOOGLE_API_KEY: Get an API key [here][google-api-key]. Only required if + getting the forecast for an arbitrary location. +- DEFAULT_LOCATION +- DEFAULT_LAT_LONG: Required if GOOGLE_API_KEY is not used. Format: `lat,long`. + +[forecast-api-key]: https://developer.forecast.io/register +[google-api-key]: https://developers.google.com/maps/documentation/geocoding/#api_key + +# TODO + +- Sparklines for precipitation? +- Make installation easier +- Handle errors gracefully +- Caching? (Probably unnecessary...) + +# Attributions + +- Icons from [Climacons](http://adamwhitcroft.com/climacons/) diff --git a/alfred.rb b/alfred.rb new file mode 100644 index 0000000..037e071 --- /dev/null +++ b/alfred.rb @@ -0,0 +1,44 @@ +class Items < DelegateClass(Array) + attr_reader :items + + def initialize + @items = [] + super(@items) + end + + def to_s + ERB.new(<<-XML).result(binding) + + + <%= items.map {|item| item.to_s.split("\n").map {|line| ' ' << line }}.join("\n").strip %> + + XML + end +end + +class Item + attr_reader *%i[ uid arg valid + title subtitle icon ] + def initialize(**kwargs) + @uid = kwargs.fetch(:uid).to_s.encode(xml: :attr) + @arg = kwargs[:arg].to_s.encode(xml: :attr) + @valid = kwargs.fetch(:valid, false) ? 'yes' : 'no' + @title = kwargs.fetch(:title).encode(xml: :text) + @subtitle = kwargs[:subtitle] && kwargs[:subtitle].encode(xml: :text) + @icon = kwargs[:icon] && kwargs[:icon].encode(xml: :text) + end + + def to_s + ERB.new(<<-XML, nil, '%>').result(binding) + uid=<%= uid %> valid="<%= valid %>"> + <%= title %> +% if subtitle + <%= subtitle %> +% end +% if icon + <%= icon %> +% end + + XML + end +end diff --git a/forecast.rb b/forecast.rb new file mode 100644 index 0000000..7a31361 --- /dev/null +++ b/forecast.rb @@ -0,0 +1,108 @@ +require 'delegate' +require 'erb' +require 'yaml' + +require_relative 'alfred' +require_relative 'forecaster' +require_relative 'location' + +ICONS = { + 'clear-day' => 'Sun', + 'clear-night' => 'Moon', + 'rain' => 'Cloud-Rain', + 'snow' => 'Cloud-Snow', + 'sleet' => 'Cloud-Snow-Alt', + 'wind' => 'Wind', + 'fog' => 'Cloud-Fog', + 'cloudy' => 'Cloud', + 'partly-cloudy-day' => 'Cloud-Sun', + 'partly-cloudy-night' => 'Cloud-Moon', +} + +Precipitation = Struct.new(:intensity, :probability) do + def self.from_forecast(forecast) + self.new(*forecast.values_at('precipIntensity', 'precipProbability')) + end + + def human_intensity + case intensity + when 0...0.002 + 'no' + when 0.002...0.017 + 'very light' + when 0.017...0.1 + 'light' + when 0.1...0.4 + 'moderate' + else + 'heavy' + end + end + + def to_s + "#{(probability*100).to_i}% chance of #{human_intensity} rain." + end +end + +query = ARGV.shift || '' +location = if query.empty? + lat, long = ENV.fetch('DEFAULT_LAT_LONG', '').split(?,) + Location.new(ENV['DEFAULT_LOCATION'], lat, long) + else + Location.new(query) + end +forecast = Forecaster.forecast(location) + +items = Items.new + +items << Item.new( + uid: :location, + arg: "#{location.lat.round(4)},#{location.long.round(4)}", + valid: true, + title: location.name, + icon: 'icons/forecast.ico', +) + +currently = forecast['currently'] +precip = Precipitation.from_forecast(currently) +subtitle = [ "#{currently['temperature'].round}°" ] +subtitle << "Feels like #{currently['apparentTemperature'].round}°" +subtitle << precip.to_s if precip.probability > 0 +items << Item.new( + uid: :currently, + title: currently['summary'], + subtitle: subtitle.join(' · '), + icon: "icons/#{ICONS[currently['icon']]}.png", +) + +minutely = forecast['minutely'] +items << Item.new( + uid: :minutely, + title: minutely['summary'], + icon: "icons/#{ICONS[minutely['icon']]}.png", +) + +hourly = forecast['hourly'] +items << Item.new( + uid: :hourly, + title: hourly['summary'], + icon: "icons/#{ICONS[hourly['icon']]}.png", +) + +forecast['daily']['data'][1..6].each do |data| + wday = Time.at(data['time']).strftime('%A') + precip = Precipitation.from_forecast(data) + + subtitle = [ "Low: #{data['apparentTemperatureMin'].round}°", + "High: #{data['apparentTemperatureMax'].round}°" ] + subtitle << precip.to_s if precip.probability > 0 + + items << Item.new( + uid: wday, + title: "#{wday} - #{data['summary']}", + subtitle: subtitle.join(' · '), + icon: "icons/#{ICONS[data['icon']]}.png", + ) +end + +puts items.to_s diff --git a/forecaster.rb b/forecaster.rb new file mode 100644 index 0000000..5853b52 --- /dev/null +++ b/forecaster.rb @@ -0,0 +1,21 @@ +require 'json' +require 'open-uri' + +Forecaster = Struct.new(:api_key) do + def self.forecast(location) + forecaster.forecast(location) + end + + def self.forecaster + return @forecaster if defined?(@forecaster) + + @forecaster = self.new(ENV['FORECAST_API_KEY']) + end + + def forecast(location) + lat, long = location.lat, location.long + url = "https://api.forecast.io/forecast/#{api_key}/#{lat},#{long}" + response = JSON.load(open(url)) + end +end + diff --git a/geocoder.rb b/geocoder.rb new file mode 100644 index 0000000..83e2ff9 --- /dev/null +++ b/geocoder.rb @@ -0,0 +1,28 @@ +require 'json' +require 'open-uri' +require 'uri' + +Geocoder = Struct.new(:api_key) do + def self.geocode(location) + geocoder.geocode(location) + end + + def self.geocoder + return @geocoder if defined?(@geocoder) + + @geocoder = self.new(ENV['GOOGLE_API_KEY']) + end + + def geocode(location) + url = 'https://maps.googleapis.com/maps/api/geocode/json' + query = URI.encode_www_form(address: location, api_key: api_key) + response = JSON.load(open("#{url}?#{query}")) + result = response['results'][0] + + name = result['formatted_address'] + location = result['geometry']['location'] + lat, long = location.values_at('lat', 'lng') + + [name, lat, long] + end +end diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..1d96821 Binary files /dev/null and b/icon.png differ diff --git a/icons/Cloud-Download.png b/icons/Cloud-Download.png new file mode 100644 index 0000000..4187ce2 Binary files /dev/null and b/icons/Cloud-Download.png differ diff --git a/icons/Cloud-Drizzle-Alt.png b/icons/Cloud-Drizzle-Alt.png new file mode 100644 index 0000000..31f4e8d Binary files /dev/null and b/icons/Cloud-Drizzle-Alt.png differ diff --git a/icons/Cloud-Drizzle-Moon-Alt.png b/icons/Cloud-Drizzle-Moon-Alt.png new file mode 100644 index 0000000..d51e635 Binary files /dev/null and b/icons/Cloud-Drizzle-Moon-Alt.png differ diff --git a/icons/Cloud-Drizzle-Moon.png b/icons/Cloud-Drizzle-Moon.png new file mode 100644 index 0000000..079ae74 Binary files /dev/null and b/icons/Cloud-Drizzle-Moon.png differ diff --git a/icons/Cloud-Drizzle-Sun-Alt.png b/icons/Cloud-Drizzle-Sun-Alt.png new file mode 100644 index 0000000..f40345e Binary files /dev/null and b/icons/Cloud-Drizzle-Sun-Alt.png differ diff --git a/icons/Cloud-Drizzle-Sun.png b/icons/Cloud-Drizzle-Sun.png new file mode 100644 index 0000000..bc475f4 Binary files /dev/null and b/icons/Cloud-Drizzle-Sun.png differ diff --git a/icons/Cloud-Drizzle.png b/icons/Cloud-Drizzle.png new file mode 100644 index 0000000..eadc3e3 Binary files /dev/null and b/icons/Cloud-Drizzle.png differ diff --git a/icons/Cloud-Fog-Alt.png b/icons/Cloud-Fog-Alt.png new file mode 100644 index 0000000..24e2d6f Binary files /dev/null and b/icons/Cloud-Fog-Alt.png differ diff --git a/icons/Cloud-Fog-Moon-Alt.png b/icons/Cloud-Fog-Moon-Alt.png new file mode 100644 index 0000000..1359eee Binary files /dev/null and b/icons/Cloud-Fog-Moon-Alt.png differ diff --git a/icons/Cloud-Fog-Moon.png b/icons/Cloud-Fog-Moon.png new file mode 100644 index 0000000..bf148f9 Binary files /dev/null and b/icons/Cloud-Fog-Moon.png differ diff --git a/icons/Cloud-Fog-Sun-Alt.png b/icons/Cloud-Fog-Sun-Alt.png new file mode 100644 index 0000000..5179981 Binary files /dev/null and b/icons/Cloud-Fog-Sun-Alt.png differ diff --git a/icons/Cloud-Fog-Sun.png b/icons/Cloud-Fog-Sun.png new file mode 100644 index 0000000..cbc7e7f Binary files /dev/null and b/icons/Cloud-Fog-Sun.png differ diff --git a/icons/Cloud-Fog.png b/icons/Cloud-Fog.png new file mode 100644 index 0000000..b02b45e Binary files /dev/null and b/icons/Cloud-Fog.png differ diff --git a/icons/Cloud-Hail-Alt.png b/icons/Cloud-Hail-Alt.png new file mode 100644 index 0000000..76cd34e Binary files /dev/null and b/icons/Cloud-Hail-Alt.png differ diff --git a/icons/Cloud-Hail-Moon-Alt.png b/icons/Cloud-Hail-Moon-Alt.png new file mode 100644 index 0000000..5671d7c Binary files /dev/null and b/icons/Cloud-Hail-Moon-Alt.png differ diff --git a/icons/Cloud-Hail-Moon.png b/icons/Cloud-Hail-Moon.png new file mode 100644 index 0000000..23b98d1 Binary files /dev/null and b/icons/Cloud-Hail-Moon.png differ diff --git a/icons/Cloud-Hail-Sun-Alt.png b/icons/Cloud-Hail-Sun-Alt.png new file mode 100644 index 0000000..4704ebd Binary files /dev/null and b/icons/Cloud-Hail-Sun-Alt.png differ diff --git a/icons/Cloud-Hail-Sun.png b/icons/Cloud-Hail-Sun.png new file mode 100644 index 0000000..66d052b Binary files /dev/null and b/icons/Cloud-Hail-Sun.png differ diff --git a/icons/Cloud-Hail.png b/icons/Cloud-Hail.png new file mode 100644 index 0000000..9d03310 Binary files /dev/null and b/icons/Cloud-Hail.png differ diff --git a/icons/Cloud-Lightning-Moon.png b/icons/Cloud-Lightning-Moon.png new file mode 100644 index 0000000..f02c182 Binary files /dev/null and b/icons/Cloud-Lightning-Moon.png differ diff --git a/icons/Cloud-Lightning-Sun.png b/icons/Cloud-Lightning-Sun.png new file mode 100644 index 0000000..9768843 Binary files /dev/null and b/icons/Cloud-Lightning-Sun.png differ diff --git a/icons/Cloud-Lightning.png b/icons/Cloud-Lightning.png new file mode 100644 index 0000000..01a3725 Binary files /dev/null and b/icons/Cloud-Lightning.png differ diff --git a/icons/Cloud-Moon.png b/icons/Cloud-Moon.png new file mode 100644 index 0000000..78fd657 Binary files /dev/null and b/icons/Cloud-Moon.png differ diff --git a/icons/Cloud-Rain-Alt.png b/icons/Cloud-Rain-Alt.png new file mode 100644 index 0000000..e0ae91e Binary files /dev/null and b/icons/Cloud-Rain-Alt.png differ diff --git a/icons/Cloud-Rain-Moon-Alt.png b/icons/Cloud-Rain-Moon-Alt.png new file mode 100644 index 0000000..3dee696 Binary files /dev/null and b/icons/Cloud-Rain-Moon-Alt.png differ diff --git a/icons/Cloud-Rain-Moon.png b/icons/Cloud-Rain-Moon.png new file mode 100644 index 0000000..752b309 Binary files /dev/null and b/icons/Cloud-Rain-Moon.png differ diff --git a/icons/Cloud-Rain-Sun-Alt.png b/icons/Cloud-Rain-Sun-Alt.png new file mode 100644 index 0000000..3d394c6 Binary files /dev/null and b/icons/Cloud-Rain-Sun-Alt.png differ diff --git a/icons/Cloud-Rain-Sun.png b/icons/Cloud-Rain-Sun.png new file mode 100644 index 0000000..874b6f2 Binary files /dev/null and b/icons/Cloud-Rain-Sun.png differ diff --git a/icons/Cloud-Rain.png b/icons/Cloud-Rain.png new file mode 100644 index 0000000..ac81b60 Binary files /dev/null and b/icons/Cloud-Rain.png differ diff --git a/icons/Cloud-Refresh.png b/icons/Cloud-Refresh.png new file mode 100644 index 0000000..8131b78 Binary files /dev/null and b/icons/Cloud-Refresh.png differ diff --git a/icons/Cloud-Snow-Alt.png b/icons/Cloud-Snow-Alt.png new file mode 100644 index 0000000..397934c Binary files /dev/null and b/icons/Cloud-Snow-Alt.png differ diff --git a/icons/Cloud-Snow-Moon-Alt.png b/icons/Cloud-Snow-Moon-Alt.png new file mode 100644 index 0000000..0c98467 Binary files /dev/null and b/icons/Cloud-Snow-Moon-Alt.png differ diff --git a/icons/Cloud-Snow-Moon.png b/icons/Cloud-Snow-Moon.png new file mode 100644 index 0000000..0627039 Binary files /dev/null and b/icons/Cloud-Snow-Moon.png differ diff --git a/icons/Cloud-Snow-Sun-Alt.png b/icons/Cloud-Snow-Sun-Alt.png new file mode 100644 index 0000000..11468ea Binary files /dev/null and b/icons/Cloud-Snow-Sun-Alt.png differ diff --git a/icons/Cloud-Snow-Sun.png b/icons/Cloud-Snow-Sun.png new file mode 100644 index 0000000..1aad15d Binary files /dev/null and b/icons/Cloud-Snow-Sun.png differ diff --git a/icons/Cloud-Snow.png b/icons/Cloud-Snow.png new file mode 100644 index 0000000..dfc8731 Binary files /dev/null and b/icons/Cloud-Snow.png differ diff --git a/icons/Cloud-Sun.png b/icons/Cloud-Sun.png new file mode 100644 index 0000000..09e754c Binary files /dev/null and b/icons/Cloud-Sun.png differ diff --git a/icons/Cloud-Upload.png b/icons/Cloud-Upload.png new file mode 100644 index 0000000..8f88ab3 Binary files /dev/null and b/icons/Cloud-Upload.png differ diff --git a/icons/Cloud-Wind-Moon.png b/icons/Cloud-Wind-Moon.png new file mode 100644 index 0000000..b837e38 Binary files /dev/null and b/icons/Cloud-Wind-Moon.png differ diff --git a/icons/Cloud-Wind-Sun.png b/icons/Cloud-Wind-Sun.png new file mode 100644 index 0000000..cc0b3e6 Binary files /dev/null and b/icons/Cloud-Wind-Sun.png differ diff --git a/icons/Cloud-Wind.png b/icons/Cloud-Wind.png new file mode 100644 index 0000000..929b81a Binary files /dev/null and b/icons/Cloud-Wind.png differ diff --git a/icons/Cloud.png b/icons/Cloud.png new file mode 100644 index 0000000..9419d36 Binary files /dev/null and b/icons/Cloud.png differ diff --git a/icons/Compass-East.png b/icons/Compass-East.png new file mode 100644 index 0000000..6468a60 Binary files /dev/null and b/icons/Compass-East.png differ diff --git a/icons/Compass-North.png b/icons/Compass-North.png new file mode 100644 index 0000000..417066e Binary files /dev/null and b/icons/Compass-North.png differ diff --git a/icons/Compass-South.png b/icons/Compass-South.png new file mode 100644 index 0000000..f5a7484 Binary files /dev/null and b/icons/Compass-South.png differ diff --git a/icons/Compass-West.png b/icons/Compass-West.png new file mode 100644 index 0000000..22d9eac Binary files /dev/null and b/icons/Compass-West.png differ diff --git a/icons/Compass.png b/icons/Compass.png new file mode 100644 index 0000000..12ffc33 Binary files /dev/null and b/icons/Compass.png differ diff --git a/icons/Degrees-Celcius.png b/icons/Degrees-Celcius.png new file mode 100644 index 0000000..7e8e593 Binary files /dev/null and b/icons/Degrees-Celcius.png differ diff --git a/icons/Degrees-Fahrenheit.png b/icons/Degrees-Fahrenheit.png new file mode 100644 index 0000000..cfba4a5 Binary files /dev/null and b/icons/Degrees-Fahrenheit.png differ diff --git a/icons/Moon-First-Quarter.png b/icons/Moon-First-Quarter.png new file mode 100644 index 0000000..eb5db64 Binary files /dev/null and b/icons/Moon-First-Quarter.png differ diff --git a/icons/Moon-Full.png b/icons/Moon-Full.png new file mode 100644 index 0000000..d59ab86 Binary files /dev/null and b/icons/Moon-Full.png differ diff --git a/icons/Moon-Last-Quarter.png b/icons/Moon-Last-Quarter.png new file mode 100644 index 0000000..04823cc Binary files /dev/null and b/icons/Moon-Last-Quarter.png differ diff --git a/icons/Moon-New.png b/icons/Moon-New.png new file mode 100644 index 0000000..1ac14eb Binary files /dev/null and b/icons/Moon-New.png differ diff --git a/icons/Moon-Waning-Crescent.png b/icons/Moon-Waning-Crescent.png new file mode 100644 index 0000000..46b4b4b Binary files /dev/null and b/icons/Moon-Waning-Crescent.png differ diff --git a/icons/Moon-Waning-Gibbous.png b/icons/Moon-Waning-Gibbous.png new file mode 100644 index 0000000..5916506 Binary files /dev/null and b/icons/Moon-Waning-Gibbous.png differ diff --git a/icons/Moon-Waxing-Crescent.png b/icons/Moon-Waxing-Crescent.png new file mode 100644 index 0000000..8f02971 Binary files /dev/null and b/icons/Moon-Waxing-Crescent.png differ diff --git a/icons/Moon-Waxing-Gibbous.png b/icons/Moon-Waxing-Gibbous.png new file mode 100644 index 0000000..67daddb Binary files /dev/null and b/icons/Moon-Waxing-Gibbous.png differ diff --git a/icons/Moon.png b/icons/Moon.png new file mode 100644 index 0000000..8f55b3f Binary files /dev/null and b/icons/Moon.png differ diff --git a/icons/Shades.png b/icons/Shades.png new file mode 100644 index 0000000..bf979e5 Binary files /dev/null and b/icons/Shades.png differ diff --git a/icons/Snowflake.png b/icons/Snowflake.png new file mode 100644 index 0000000..380f49d Binary files /dev/null and b/icons/Snowflake.png differ diff --git a/icons/Sun-Low.png b/icons/Sun-Low.png new file mode 100644 index 0000000..2b3cd27 Binary files /dev/null and b/icons/Sun-Low.png differ diff --git a/icons/Sun-Lower.png b/icons/Sun-Lower.png new file mode 100644 index 0000000..4696a7b Binary files /dev/null and b/icons/Sun-Lower.png differ diff --git a/icons/Sun.png b/icons/Sun.png new file mode 100644 index 0000000..b7fbb7d Binary files /dev/null and b/icons/Sun.png differ diff --git a/icons/Sunrise.png b/icons/Sunrise.png new file mode 100644 index 0000000..bbb7e27 Binary files /dev/null and b/icons/Sunrise.png differ diff --git a/icons/Sunset.png b/icons/Sunset.png new file mode 100644 index 0000000..4919d59 Binary files /dev/null and b/icons/Sunset.png differ diff --git a/icons/Thermometer-100.png b/icons/Thermometer-100.png new file mode 100644 index 0000000..4ae9592 Binary files /dev/null and b/icons/Thermometer-100.png differ diff --git a/icons/Thermometer-25.png b/icons/Thermometer-25.png new file mode 100644 index 0000000..43f1655 Binary files /dev/null and b/icons/Thermometer-25.png differ diff --git a/icons/Thermometer-50.png b/icons/Thermometer-50.png new file mode 100644 index 0000000..0ab9fad Binary files /dev/null and b/icons/Thermometer-50.png differ diff --git a/icons/Thermometer-75.png b/icons/Thermometer-75.png new file mode 100644 index 0000000..3d81d8a Binary files /dev/null and b/icons/Thermometer-75.png differ diff --git a/icons/Thermometer-Zero.png b/icons/Thermometer-Zero.png new file mode 100644 index 0000000..a0d446b Binary files /dev/null and b/icons/Thermometer-Zero.png differ diff --git a/icons/Thermometer.png b/icons/Thermometer.png new file mode 100644 index 0000000..580a9f3 Binary files /dev/null and b/icons/Thermometer.png differ diff --git a/icons/Tornado.png b/icons/Tornado.png new file mode 100644 index 0000000..b0d9a6a Binary files /dev/null and b/icons/Tornado.png differ diff --git a/icons/Umbrella.png b/icons/Umbrella.png new file mode 100644 index 0000000..73d8666 Binary files /dev/null and b/icons/Umbrella.png differ diff --git a/icons/Wind.png b/icons/Wind.png new file mode 100644 index 0000000..e7bef73 Binary files /dev/null and b/icons/Wind.png differ diff --git a/icons/forecast.ico b/icons/forecast.ico new file mode 100644 index 0000000..69040d4 Binary files /dev/null and b/icons/forecast.ico differ diff --git a/info.plist b/info.plist new file mode 100644 index 0000000..b71091c --- /dev/null +++ b/info.plist @@ -0,0 +1,100 @@ + + + + + bundleid + com.kejadlen.forecast + category + Internet + connections + + 2A5C0A87-204E-49EA-94A7-8E62BB4EFD8A + + + destinationuid + 5E2D96BA-31B2-4800-9A2B-B999285680A0 + modifiers + 0 + modifiersubtext + + + + + createdby + Alpha Chen + description + + disabled + + name + Forecast + objects + + + config + + plusspaces + + url + http://forecast.io/#/f/{query} + utf8 + + + type + alfred.workflow.action.openurl + uid + 5E2D96BA-31B2-4800-9A2B-B999285680A0 + version + 0 + + + config + + argumenttype + 1 + escaping + 127 + keyword + forecast + runningsubtext + Retriving location/weather... + script + export FORECAST_API_KEY= +export GOOGLE_API_KEY= +export DEFAULT_LOCATION="Seattle, WA" + +ruby forecast.rb {query} + title + Forecast + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 2A5C0A87-204E-49EA-94A7-8E62BB4EFD8A + version + 0 + + + readme + + uidata + + 2A5C0A87-204E-49EA-94A7-8E62BB4EFD8A + + ypos + 10 + + 5E2D96BA-31B2-4800-9A2B-B999285680A0 + + ypos + 10 + + + webaddress + http://github.com/kejadlen/forecast.workflow + + diff --git a/location.rb b/location.rb new file mode 100644 index 0000000..bbe7b2b --- /dev/null +++ b/location.rb @@ -0,0 +1,16 @@ +require_relative 'geocoder' + +class Location + attr_accessor :name, :lat, :long, :geocoder + + def initialize(name, lat=nil, long=nil, geocoder=Geocoder) + @name, @lat, @long, @geocoder = name, lat, long, geocoder + + geocode! unless lat && long + end + + def geocode! + self.name, self.lat, self.long = geocoder.geocode(name) + end +end + diff --git a/spark.rb b/spark.rb new file mode 100644 index 0000000..ec697fa --- /dev/null +++ b/spark.rb @@ -0,0 +1,17 @@ +class Spark + TICKS = %w[▁ ▂ ▃ ▄ ▅ ▆ ▇ █] + + attr_reader :data + + def initialize(*data) + @data = data + end + + def to_s + min = data.min + max = data.max + range = (max - min).to_f + graph = data.map {|i| TICKS[(TICKS.size - 1) * (i - min) / range] }.join + "#{min} #{graph} #{max}" + end +end