coffeeoutside 0.2.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aacb528c83db527b5a8ce464cbf5992ffd5eabb7166d5ba9050d5132ff3b4ddb
4
- data.tar.gz: 03167aa72764c2df28ec99e1e1feefc16b54e034bd0ca5197aefeac53f129d7b
3
+ metadata.gz: 95c0295fadc19a7ab1d107e9b28560cc1228cb54dd2de613563cc00b44402700
4
+ data.tar.gz: 24d8a3f2dd2fb3227228b21e7f9ba12e72d56b0c126a3b8cd32e04c9526c145d
5
5
  SHA512:
6
- metadata.gz: d93a2a356f66be6c72e966b6e3793166f57b825a796863f0f216e86eb941b1be8740a8dcaf77b73d57a53e6bba636ca132254ffe9a77ad4858700d1074c76c29
7
- data.tar.gz: 7d3a972514ce340b34d50cc1b4149c14ff88f78effa60aea9ac66cdf0d79b2abcc5ff70490521456f6cc2a7b1a108ab59ed54ec4d745a0ecfbb711fd5cb21052
6
+ metadata.gz: bdd636bb7d5b8708e847b9e0782c5cc3ad6b0a09fe3133c16e2fe6135128aac974d90ff768f0cb641a7284039ec8273a4f4b68e45c3aa727c9462cca1070eeab
7
+ data.tar.gz: bee8a49d1eb6181c7dc1222b4478e48570e5f9ae4231dc4cf7eb94b4640d5e9e0e454767b927a795bdbe445a42c21c55c307b514048a99522ea0a4682001364c
@@ -0,0 +1,25 @@
1
+ name: Ruby
2
+ on:
3
+ push:
4
+ branches: [ main ]
5
+ pull_request:
6
+ branches: [ main ]
7
+ permissions:
8
+ contents: read
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ env:
13
+ BUNDLE_WITH: development
14
+ strategy:
15
+ matrix:
16
+ ruby-version: ['2.5.1', '3.0', '3.1']
17
+ steps:
18
+ - uses: actions/checkout@v3
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby-version }}
23
+ bundler-cache: true
24
+ - name: Run tests
25
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -1,5 +1,7 @@
1
+ *.gem
1
2
  *.ics
2
3
  /.bundle
4
+ /coverage/
3
5
  /vendor
4
6
  Gemfile.lock
5
7
  config.yaml
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ inherit_gem:
2
+ dc-rubocop: ruby25.yml
data/Gemfile CHANGED
@@ -1,24 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
7
  group :serverhack, optional: true do
8
- # TODO better handling of this
9
- gem 'http', '= 4.0.0'
8
+ # TODO: better handling of this
9
+ gem "http", "= 4.0.0"
10
10
  end
11
11
 
12
12
  group :development, optional: true do
13
13
  # TODO: submit Ruby 3.0 fixes upstream
14
- gem 'guard'
15
- gem 'guard-minitest'
16
- gem 'kwalify', '= 0.7.2'
17
- gem 'minitest'
18
- gem 'rake'
19
-
20
- # soon
21
- gem 'rubocop'
22
- # gem 'guard-rubocop'
23
- # gem 'rubocop-minitest'
14
+ gem "dc-devtools", "~> 0.5"
15
+ gem "dc-kwalify", "~> 1.0.0"
24
16
  end
data/Guardfile CHANGED
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- directories %w[lib test] \
4
- .select { |d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist") }
3
+ directories(%w[lib test].select { |d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist") })
5
4
 
6
- guard :minitest do
7
- watch(%r{^test/test_(.*)\.rb$}) { 'test' }
8
- watch(%r{^lib/coffeeoutside/(.*)\.rb$}) { 'test' }
9
- watch(%r{^lib/coffeeoutside\.rb$}) { 'test' }
10
- watch(%r{^test/helper\.rb$}) { 'test' }
5
+ guard :rake, task: "default" do
6
+ watch(%r{^test/test_(.*)\.rb$})
7
+ watch(%r{^lib/coffeeoutside/(.*)\.rb$})
8
+ watch(%r{^lib/coffeeoutside\.rb$})
11
9
  end
data/README.md CHANGED
@@ -12,9 +12,6 @@ bundle install
12
12
  bundle exec bin/coffeeoutsidebot
13
13
  ```
14
14
 
15
- ## Twitter integration
16
- You can get the necessary API keys at https://dev.twitter.com/
17
-
18
15
  ## OpenWeatherMap integration
19
16
  You can get an API key at https://openweathermap.org/price
20
17
 
data/Rakefile CHANGED
@@ -1,12 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
4
- require 'rake/testtask'
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+ require "dc_rake"
5
6
 
6
7
  Rake::TestTask.new(:test) do |t|
7
- t.libs << 'test'
8
- t.libs << 'lib'
9
- t.test_files = FileList['test/**/*_test.rb']
8
+ t.libs << "test"
9
+ t.libs << "lib"
10
+ t.test_files = FileList["test/**/test_*.rb"]
10
11
  end
11
12
 
12
- task default: %i[test]
13
+ task :kwalify do
14
+ sh "kwalify -f locations.schema.yaml locations.yaml"
15
+ end
16
+
17
+ task default: %i[test rubocop kwalify]
data/bin/coffeeoutsidebot CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'coffeeoutside'
5
- include CoffeeOutside
4
+ require "coffeeoutside"
5
+ include CoffeeOutside # rubocop:disable Style/MixinUsage
6
6
 
7
7
  CoffeeOutside.main
data/bin/console CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'bundler/setup'
5
- require 'coffeeoutside'
4
+ require "bundler/setup"
5
+ require "coffeeoutside"
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
@@ -11,5 +11,5 @@ require 'coffeeoutside'
11
11
  # require "pry"
12
12
  # Pry.start
13
13
 
14
- require 'irb'
14
+ require "irb"
15
15
  IRB.start(__FILE__)
@@ -1,32 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lib/coffeeoutside/version'
3
+ require_relative "lib/coffeeoutside/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = 'coffeeoutside'
6
+ spec.name = "coffeeoutside"
7
7
  spec.version = CoffeeOutside::VERSION
8
- spec.authors = ['David Crosby']
8
+ spec.authors = ["David Crosby"]
9
9
 
10
- spec.summary = 'The CoffeeOutside bot'
11
- spec.description = 'The CoffeeOutside bot helps choose a coffee location based on weather and other inputs'
12
- spec.homepage = 'https://coffeeoutside.bike'
13
- spec.license = 'MIT'
14
- spec.required_ruby_version = '>= 2.5.0'
10
+ spec.summary = "The CoffeeOutside bot"
11
+ spec.description = "The CoffeeOutside bot helps choose a coffee location based on weather and other inputs"
12
+ spec.homepage = "https://coffeeoutside.bike"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 2.5.0"
15
15
 
16
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
16
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
17
17
 
18
- spec.metadata['homepage_uri'] = spec.homepage
19
- spec.metadata['source_code_uri'] = 'https://github.com/yycbike/coffeeoutside'
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = "https://github.com/yycbike/coffeeoutside"
20
20
 
21
21
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
23
23
  end
24
- spec.bindir = 'exe'
24
+ spec.bindir = "exe"
25
25
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
26
- spec.require_paths = ['lib']
26
+ spec.require_paths = ["lib"]
27
27
 
28
- spec.add_dependency 'icalendar', '= 2.7.1'
29
- spec.add_dependency 'openweathermap', '= 0.2.3'
30
- spec.add_dependency 'rss', '= 0.2.7'
31
- spec.add_dependency 'twitter', '= 7.0.0'
28
+ spec.add_dependency "icalendar", "= 2.7.1"
29
+ spec.add_dependency "openweathermap", "= 0.2.3"
30
+ spec.add_dependency "rss", "= 0.2.7"
31
+ spec.metadata["rubygems_mfa_required"] = "true"
32
32
  end
data/config.example.yaml CHANGED
@@ -1,6 +1,6 @@
1
1
  production: false
2
2
  dispatchers:
3
- twitter:
3
+ service:
4
4
  consumer_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
5
5
  consumer_key: xxxxxxxxxxxxxxxxxxxxxxxxxx
6
6
  token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
@@ -23,7 +23,7 @@ module CoffeeOutside
23
23
  end
24
24
 
25
25
  def notify_production
26
- raise 'notify_production must be overridden'
26
+ raise "notify_production must be overridden"
27
27
  end
28
28
 
29
29
  def debug_method
@@ -33,7 +33,7 @@ module CoffeeOutside
33
33
  end
34
34
 
35
35
  def notify_debug
36
- raise 'notify_production must be overridden'
36
+ raise "notify_production must be overridden"
37
37
  end
38
38
  end
39
39
  end
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dispatcher'
4
- require 'icalendar'
3
+ require_relative "dispatcher"
4
+ require "icalendar"
5
5
 
6
6
  module CoffeeOutside
7
7
  class IcalDispatcher < DispatcherBase
8
8
  def generate_ical_string
9
- format = '%Y%m%dT%H%M%S'
10
- tzid = 'America/Edmonton'
9
+ format = "%Y%m%dT%H%M%S"
10
+ tzid = "America/Edmonton"
11
11
 
12
12
  # Create a calendar with an event (standard method)
13
13
  cal = Icalendar::Calendar.new
14
14
  cal.event do |e|
15
- e.dtstart = Icalendar::Values::DateTime.new @start_time.strftime(format), 'tzid' => tzid
16
- e.dtend = Icalendar::Values::DateTime.new @end_time.strftime(format), 'tzid' => tzid
15
+ e.dtstart = Icalendar::Values::DateTime.new @start_time.strftime(format), "tzid" => tzid
16
+ e.dtend = Icalendar::Values::DateTime.new @end_time.strftime(format), "tzid" => tzid
17
17
  e.summary = "CoffeeOutside - #{@location.name}"
18
18
  e.location = @location.name
19
19
  end
@@ -21,7 +21,7 @@ module CoffeeOutside
21
21
  end
22
22
 
23
23
  def notify_production
24
- i = File.open('yyc.ics', 'w')
24
+ i = File.open("yyc.ics", "w")
25
25
  i.write(generate_ical_string)
26
26
  end
27
27
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dispatcher'
4
- require 'json'
3
+ require_relative "dispatcher"
4
+ require "json"
5
5
 
6
6
  module CoffeeOutside
7
7
  class JsonDispatcher < DispatcherBase
@@ -14,7 +14,7 @@ module CoffeeOutside
14
14
  end
15
15
 
16
16
  def notify_production
17
- i = File.open('yyc.json', 'w')
17
+ i = File.open("yyc.json", "w")
18
18
  i.write(generate_json_blob)
19
19
  end
20
20
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dispatcher'
4
- require 'rss'
3
+ require_relative "dispatcher"
4
+ require "rss"
5
5
 
6
6
  module CoffeeOutside
7
7
  class RssDispatcher < DispatcherBase
@@ -13,18 +13,18 @@ module CoffeeOutside
13
13
  end
14
14
 
15
15
  def generate_rss_string
16
- RSS::Maker.make('2.0') do |maker|
17
- maker.channel.language = 'en'
18
- maker.channel.author = 'CoffeeOutsideBot'
16
+ RSS::Maker.make("2.0") do |maker|
17
+ maker.channel.language = "en"
18
+ maker.channel.author = "CoffeeOutsideBot"
19
19
  maker.channel.updated = Time.now.to_s
20
- maker.channel.about = 'https://coffeeoutside.bike/yyc.rss'
21
- maker.channel.link = 'https://coffeeoutside.bike/yyc.rss'
22
- maker.channel.description = 'CoffeeOutside is a weekly meetup where Calgarians bike/walk/run/rollerblade to a location, drink coffee/tea/some hot or cold beverage, and shoot the breeze'
23
- maker.channel.title = 'CoffeeOutside'
20
+ maker.channel.about = "https://coffeeoutside.bike/yyc.rss"
21
+ maker.channel.link = "https://coffeeoutside.bike/yyc.rss"
22
+ maker.channel.description = "CoffeeOutside is a weekly meetup where Calgarians bike/walk/run/rollerblade to a location, drink coffee/tea/some hot or cold beverage, and shoot the breeze" # rubocop:disable Layout/LineLength
23
+ maker.channel.title = "CoffeeOutside"
24
24
 
25
25
  maker.items.new_item do |item|
26
26
  item.link = @location.url if @location.url
27
- item.title = "Location for #{@start_time.strftime('%Y-%m-%d')}: #{@location.name}"
27
+ item.title = "Location for #{@start_time.strftime("%Y-%m-%d")}: #{@location.name}"
28
28
  item.description = generate_description
29
29
  item.updated = Time.now.to_s
30
30
  end
@@ -32,7 +32,7 @@ module CoffeeOutside
32
32
  end
33
33
 
34
34
  def notify_production
35
- i = File.open('yyc.rss', 'w')
35
+ i = File.open("yyc.rss", "w")
36
36
  i.write(generate_rss_string)
37
37
  end
38
38
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dispatcher'
3
+ require_relative "dispatcher"
4
4
 
5
5
  module CoffeeOutside
6
6
  class StdoutDispatcher < DispatcherBase
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoffeeOutside
4
+ module EventTime
5
+ def self.next_friday
6
+ # TODO: this is gross...
7
+ @next_friday ||= Date.today + [5, 4, 3, 2, 1, 7, 6][Date.today.wday]
8
+ end
9
+
10
+ def self.start_time
11
+ DateTime.new(
12
+ next_friday.year, next_friday.month, next_friday.day,
13
+ 7, 30, 0,
14
+ "-07:00"
15
+ )
16
+ end
17
+
18
+ def self.end_time
19
+ DateTime.new(
20
+ next_friday.year, next_friday.month, next_friday.day,
21
+ 8, 30, 0,
22
+ "-07:00"
23
+ )
24
+ end
25
+ end
26
+ end
@@ -1,26 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
3
+ require "yaml"
4
4
 
5
5
  module CoffeeOutside
6
6
  class Location
7
- attr_reader :name, :address, :url, :nearby_coffee
7
+ attr_reader :name, :location_hint, :address, :url, :nearby_coffee
8
8
 
9
9
  def initialize(params)
10
- if params['name']
11
- @name = params['name']
10
+ if params["name"]
11
+ @name = params["name"]
12
12
  else
13
- raise 'Location class requires name key'
13
+ raise "Location class requires name key"
14
14
  end
15
- @paused = params['paused'] || false
16
- @nearby_coffee = params['nearby_coffee'] || []
17
- @url = params['url'] if params['url']
18
- @address = params['address'] if params['address']
15
+ @paused = params["paused"] || false
16
+ @nearby_coffee = params["nearby_coffee"] || []
17
+ @url = params["url"] if params["url"]
18
+ @address = params["address"] if params["address"]
19
+ @location_hint = params["location_hint"] if params["location_hint"]
19
20
 
20
21
  # Forecast related
21
- @rainy_day = params['rainy_day'] || false
22
- @high_limit = params['high_limit'] if params['high_limit']
23
- @low_limit = params['low_limit'] if params['low_limit']
22
+ @rainy_day = params["rainy_day"] || false
23
+ @high_limit = params["high_limit"] if params["high_limit"]
24
+ @low_limit = params["low_limit"] if params["low_limit"]
24
25
 
25
26
  # Save params for any dispatcher-specific values
26
27
  @params = params
@@ -32,13 +33,10 @@ module CoffeeOutside
32
33
 
33
34
  def weather_appropriate?(forecast)
34
35
  # TODO: stderr reasons?
35
- if forecast.rainy? && !@rainy_day
36
- return false
37
- elsif @low_limit && (forecast.temperature < @low_limit)
38
- return false
39
- elsif @high_limit && (forecast.temperature > @high_limit)
40
- return false
41
- end
36
+
37
+ return false if (forecast.rainy? && !@rainy_day) ||
38
+ (@low_limit && (forecast.temperature < @low_limit)) ||
39
+ (@high_limit && (forecast.temperature > @high_limit))
42
40
 
43
41
  true
44
42
  end
@@ -51,20 +49,20 @@ module CoffeeOutside
51
49
  class LocationFile
52
50
  attr_reader :locations
53
51
 
54
- def initialize(filename = './locations.yaml')
52
+ def initialize(filename = "./locations.yaml")
55
53
  y = YAML.load_file(filename)
56
54
  @locations = []
57
55
  y.each do |l|
58
56
  @locations.append Location.new(l)
59
57
  end
60
- @locations
58
+ @locations # rubocop:disable Lint/Void
61
59
  end
62
60
  end
63
61
 
64
62
  class OverrideFile
65
63
  attr_reader :location
66
64
 
67
- def initialize(filename = './override.yaml')
65
+ def initialize(filename = "./override.yaml")
68
66
  @filename = filename
69
67
  if ::File.exist? @filename
70
68
  @override = true
@@ -87,7 +85,7 @@ module CoffeeOutside
87
85
  class LocationChooser
88
86
  attr_reader :location
89
87
 
90
- def initialize(destructive = false, forecast)
88
+ def initialize(forecast, destructive: false)
91
89
  @location = nil
92
90
  of = OverrideFile.new
93
91
  plf = PriorLocationsFile.new
@@ -103,29 +101,32 @@ module CoffeeOutside
103
101
  # Remove paused locations
104
102
  locations.delete_if(&:paused?)
105
103
 
106
- # Remove previously selected locations
107
- prior_locations = plf.previous_locations
108
- locations.delete_if { |l| prior_locations.include? l.name }
109
-
110
104
  # Delete locations that don't meet forecast criteria
111
105
  locations.keep_if { |l| l.weather_appropriate? forecast }
112
106
 
113
107
  # Raise if no locations remaining
114
- raise 'No locations remaining!' if locations.empty?
108
+ raise "No locations remaining!" if locations.empty?
109
+
110
+ # Remove previously selected locations
111
+ prior_locations = plf.previous_locations.dup
112
+ while !prior_locations.empty? && locations.count > 1
113
+ pl = prior_locations.pop(locations.count - 1)
114
+ locations.delete_if { |l| pl.include? l.name }
115
+ end
115
116
 
116
- # Pick random location
117
+ # Pick random location if more than one remaining
117
118
  @location = locations.sample
118
119
  end
119
120
 
120
121
  # Append to prior locations list
121
122
  plf.append_location @location if destructive
122
123
 
123
- @location
124
+ @location # rubocop:disable Lint/Void
124
125
  end
125
126
  end
126
127
 
127
128
  class PriorLocationsFile
128
- def initialize(filename = './prior_locations.yaml')
129
+ def initialize(filename = "./prior_locations.yaml")
129
130
  @filename = filename
130
131
  @locations = if File.exist? filename
131
132
  YAML.load_file(filename) || []
@@ -134,13 +135,13 @@ module CoffeeOutside
134
135
  end
135
136
  end
136
137
 
137
- def previous_locations(n = 5)
138
- @locations.last n
138
+ def previous_locations
139
+ @locations
139
140
  end
140
141
 
141
142
  def append_location(location)
142
143
  @locations.append location.name
143
- f = File.open(@filename, 'w')
144
+ f = File.open(@filename, "w")
144
145
  f.write(YAML.dump(@locations))
145
146
  end
146
147
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CoffeeOutside
4
- VERSION = '0.2.2'
4
+ VERSION = "1.0.0"
5
5
  end
@@ -1,24 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'openweathermap'
3
+ require "openweathermap"
4
4
 
5
5
  module CoffeeOutside
6
6
  class OWM
7
- def initialize(config)
8
- @city_id = config['city_id']
9
- @api_key = config['api_key']
7
+ attr_accessor :result
10
8
 
11
- get_forecast
9
+ def initialize(config, time = DateTime.now)
10
+ @city_id = config["city_id"]
11
+ @api_key = config["api_key"]
12
+ @start_time = time
12
13
  end
13
14
 
14
15
  def api_call
15
- api = OpenWeatherMap::API.new(@api_key, 'en', 'metric')
16
- api.forecast(@city_id)
16
+ api = OpenWeatherMap::API.new(@api_key, "en", "metric")
17
+ @result = api.forecast(@city_id)
17
18
  end
18
19
 
19
- def get_forecast
20
- # TODO: this looks wrong, check @time!
21
- fc = api_call.forecast[2]
20
+ def closest_forecast
21
+ # Doing this as 'The Price Is Right' rules, forecast with the closest
22
+ # time to the start without going over wins.
23
+ @result.forecast.reject! { |x| x.time.to_datetime > @start_time }
24
+ @result.forecast.last
25
+ end
26
+
27
+ def parse_owm_datestring(str)
28
+ DateTime.strptime(str, "%Y-%m-%d %H-%M-%S")
29
+ end
30
+
31
+ def forecast
32
+ api_call
33
+ fc = closest_forecast
22
34
  Forecast.new(humidity: fc.humidity, temperature: fc.temperature)
23
35
  end
24
36
  end
data/lib/coffeeoutside.rb CHANGED
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
- require 'date'
5
- require_relative 'coffeeoutside/version'
6
- require_relative 'coffeeoutside/locations'
7
- require_relative 'coffeeoutside/weather'
3
+ require "yaml"
4
+ require "date"
5
+ require_relative "coffeeoutside/version"
6
+ require_relative "coffeeoutside/locations"
7
+ require_relative "coffeeoutside/weather"
8
+ require_relative "coffeeoutside/event_time"
8
9
 
9
10
  # Dispatchers
10
- %w[stdout json ical rss twitter].each do |d|
11
+ %w[stdout json ical rss].each do |d|
11
12
  require_relative "coffeeoutside/dispatchers/#{d}"
12
13
  end
13
14
 
@@ -17,11 +18,11 @@ module CoffeeOutside
17
18
  class Config
18
19
  attr_reader :dispatchers, :openweathermap
19
20
 
20
- def initialize(config_file = 'config.yaml')
21
+ def initialize(config_file = "config.yaml")
21
22
  config = YAML.load_file(config_file)
22
- @production = config['production']
23
- @dispatchers = config['dispatchers']
24
- @openweathermap = config['openweathermap']
23
+ @production = config["production"]
24
+ @dispatchers = config["dispatchers"]
25
+ @openweathermap = config["openweathermap"]
25
26
  end
26
27
 
27
28
  def production?
@@ -29,40 +30,21 @@ module CoffeeOutside
29
30
  end
30
31
  end
31
32
 
32
- def next_friday
33
- # TODO: this is gross...
34
- @next_friday ||= Date.today + [5, 4, 3, 2, 1, 7, 6][Date.today.wday]
35
- end
36
-
37
- def get_start_time
38
- DateTime.new(
39
- next_friday.year, next_friday.month, next_friday.day,
40
- 7, 30, 0
41
- )
42
- end
43
-
44
- def get_end_time
45
- DateTime.new(
46
- next_friday.year, next_friday.month, next_friday.day,
47
- 8, 30, 0
48
- )
49
- end
50
-
51
33
  def main
52
34
  config = Config.new
53
35
  if config.production?
54
- owm = OWM.new config.openweathermap
55
- forecast = owm.get_forecast
36
+ owm = OWM.new config.openweathermap, EventTime.start_time
37
+ forecast = owm.forecast
56
38
  else
39
+ # stub a forecast in since OWM is rate-limited
57
40
  forecast = Forecast.new(humidity: 0, temperature: 10)
58
41
  end
59
42
 
60
- destructive = config.production?
61
- location = LocationChooser.new(destructive, forecast).location
43
+ location = LocationChooser.new(forecast, destructive: config.production?).location
62
44
 
63
45
  dispatch = {
64
- start_time: get_start_time,
65
- end_time: get_end_time,
46
+ start_time: EventTime.start_time,
47
+ end_time: EventTime.end_time,
66
48
  forecast: forecast,
67
49
  location: location,
68
50
  production: config.production?
@@ -71,6 +53,5 @@ module CoffeeOutside
71
53
  JsonDispatcher.new(dispatch).notify
72
54
  RssDispatcher.new(dispatch).notify
73
55
  IcalDispatcher.new(dispatch).notify
74
- TwitterDispatcher.new(dispatch.merge(config.dispatchers['twitter'])).notify
75
56
  end
76
57
  end
@@ -7,6 +7,9 @@ sequence:
7
7
  desc: "Name of the meetup location"
8
8
  type: str
9
9
  required: yes
10
+ "location_hint":
11
+ desc: "Human readable 'hint' where the meetup is"
12
+ type: str
10
13
  "url":
11
14
  desc: "URL for the site. Order of preference: City of Calgary link (if park), Cafe website (if inside), Google Maps URL"
12
15
  type: str
data/locations.yaml CHANGED
@@ -1,41 +1,41 @@
1
1
  ---
2
- - name: "@LaBoulangerie4"
2
+ - name: La Boulangerie
3
3
  address: 2435 4 St SW
4
4
  high_limit: 5
5
5
  rainy_day: true
6
6
  paused: true
7
7
  - high_limit: 5
8
- name: "@SidewalkSimmons"
9
- url: http://sidewalkcitizenbakery.com/
8
+ name: Sidewalk Citizen Bakery (Simmons Building)
9
+ url: https://sidewalkcitizenbakery.com/
10
10
  rainy_day: true
11
11
  paused: true
12
12
  - url: https://alforno.ca/
13
- name: "@AlfornoYYC"
13
+ name: Alforno
14
14
  high_limit: 5
15
15
  rainy_day: true
16
- paused: true
16
+ paused: true # Opens 8AM as of 2022-11-17
17
17
  - url: https://iloveyoucoffeeshop.com/
18
- name: "@iloveyoucoffee_"
18
+ name: I Love You Coffee Shop
19
19
  high_limit: 5
20
20
  rainy_day: true
21
- paused: true
21
+ paused: true # Opens 8AM as of 2022-11-17
22
22
  - url: http://www.bayaricacafe.ca/
23
- name: "@BayaRicaCafe"
23
+ name: Baya Rica Cafe
24
24
  address: 204 7A Street NE
25
25
  high_limit: 5
26
26
  rainy_day: true
27
- paused: true
28
27
  - url: https://www.calgaryheritageroastingco.com/
29
28
  name: Calgary Heritage Roasting Company
30
29
  address: 2020 11 St SE
31
30
  high_limit: 5
32
31
  rainy_day: true
33
- paused: true
32
+ paused: true # Opens 8AM as of 2022-11-17
34
33
  - address: 420 2nd Street SW
35
34
  high_limit: 0
36
- name: "@monogramco"
35
+ name: Monogram Coffee
37
36
  rainy_day: true
38
37
  - name: Barb Scott Park
38
+ location_hint: by 13th Ave tables
39
39
  url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/Downtown-parks/Barb-Scott-Park.aspx
40
40
  low_limit: -15
41
41
  - name: Buckmaster Park
@@ -43,32 +43,40 @@
43
43
  address: 1629 21 Ave SW
44
44
  - high_limit: 0
45
45
  address: 909 10 St SE
46
- name: "@cafegravity"
46
+ name: Cafe Gravity
47
47
  rainy_day: true
48
48
  paused: true
49
49
  - high_limit: -15
50
50
  address: 1613 9th Street SW
51
51
  name: Caffe Beano
52
52
  rainy_day: true
53
- paused: false
54
53
  - name: Ca'puccini
55
54
  paused: true
56
55
  - name: CNIB Fragrant Garden
57
56
  address: 10 11A St NE
58
- low_limit: 5
59
- url: TODO
60
- paused: true
57
+ low_limit: 10
58
+ url: https://goo.gl/maps/2x2rRGgpdCdBG7am8
61
59
  - name: Central Memorial Park
62
60
  low_limit: -15
63
61
  url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/Downtown-parks/Central-Memorial-Park.aspx
64
62
  - name: Connaught Park
65
63
  low_limit: -15
66
64
  url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/Downtown-parks/Connaught-Park.aspx
67
- - name: Containr Park
65
+ - name: Gladstone Pocket Park
68
66
  address: TODO
69
- low_limit: -15
67
+ low_limit: -1
70
68
  url: TODO
71
69
  paused: true
70
+ - name: Central Library Park
71
+ location_hint: 3rd St 9th Ave corner park
72
+ address: 800 3 Street SE
73
+ low_limit: -1
74
+ url: https://calgarylibrary.ca/your-library/locations/cent/
75
+ rainy_day: true
76
+ - name: Containr Park
77
+ address: 1020 2 Ave NW
78
+ low_limit: -15
79
+ url: https://springboardperformance.com/containr
72
80
  - name: East Village Music Pavilion
73
81
  url: https://www.evexperience.com/music-pavilion
74
82
  low_limit: -10
@@ -76,7 +84,6 @@
76
84
  - name: Delta Park
77
85
  url: https://www.google.com/maps/place/Delta+Garden/@51.0521029,-114.0786464,17z/
78
86
  low_limit: -10
79
- rainy_day: false
80
87
  - name: DeVille Luxury Coffee
81
88
  paused: true
82
89
  - name: Enmax Stage on Prince's Island
@@ -89,17 +96,19 @@
89
96
  - name: Harley Hotchkiss Gardens
90
97
  low_limit: -5
91
98
  address: 611 4 St SW
92
- - name: Harvie Passage (Weir)
99
+ - name: Harvie Passage Lookout
100
+ location_hint: by the weir entrance
93
101
  low_limit: 0
94
- url: https://www.google.ca/maps/place/Harvie+Passage,+Calgary,+AB/@51.0439438,-114.0137959,15z/data=!4m2!3m1!1s0x53717ac80a6f6a1b:0xe7a331ec29495195
102
+ url: https://goo.gl/maps/jZG2saNkY1AnhbY29
95
103
  - name: Haultain Park
96
104
  low_limit: -15
97
105
  url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/Downtown-parks/Haultain-Park.aspx
98
- - name: High Park (walk your bike up)
106
+ - name: High Park
107
+ location_hint: walk your bike up
99
108
  low_limit: 0
100
109
  url: https://www.beltlineyyc.ca/highparkyyc
101
110
  - name: Horsy Park
102
- low_limit: 10
111
+ low_limit: 15
103
112
  url: https://goo.gl/maps/ido1KAcqdJGtkeVN8
104
113
  - name: Humpy Hollow Park
105
114
  url: https://www.calgary.ca/CSPS/Parks/Pages/Locations/Downtown-parks/Humpy-Hollow-Park.aspx
@@ -109,17 +118,23 @@
109
118
  url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/Downtown-parks/Olympic-Plaza.aspx
110
119
  low_limit: -15
111
120
  nearby_coffee: Ca'Puccini
112
- - name: James Short Park
121
+ - name: Harmony Park
113
122
  low_limit: -5
114
- url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/Downtown-parks/James-Short-Park.aspx
123
+ address: 115 4 Ave SW
124
+ url: https://www.calgary.ca/parks/harmony-park.html
115
125
  - name: Lougheed House Beaulieu Gardens
116
- low_limit: -5
126
+ low_limit: -2
117
127
  url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/Downtown-parks/Beaulieu-Gardens.aspx
118
- - name: McHugh Bluff
119
- low_limit: 0
120
- url: TODO
121
- paused: true
128
+ - name: Rosedale Dog Park
129
+ location_hint: benches at top of bluff
130
+ address: 1103 10 St NW
131
+ low_limit: 5
132
+ url: https://goo.gl/maps/Rpf5WTGQzyMkWSYY9
122
133
  - name: Munro Park
134
+ address: 425 18 Ave NE
135
+ url: https://www.calgary.ca/csps/parks/locations/ne-parks/munro-park.html
136
+ low_limit: 20
137
+ - name: City Hall municipal building
123
138
  url: TODO
124
139
  paused: true
125
140
  - low_limit: 10
@@ -140,7 +155,8 @@
140
155
  - name: Reader Rock Garden
141
156
  low_limit: 10
142
157
  url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/SE-parks/Reader-Rock-Garden.aspx
143
- - name: Riley Park (Stage)
158
+ - name: Riley Park
159
+ location_hint: Stage
144
160
  url: https://www.calgary.ca/csps/parks/locations/nw-parks/riley-park.html
145
161
  low_limit: -10
146
162
  rainy_day: true
@@ -168,18 +184,27 @@
168
184
  high_limit: 5
169
185
  address: 314 10th St NW
170
186
  rainy_day: true
171
- paused: true
187
+ - name: Royal Sunalta Park
188
+ location_hint: by lower swings
189
+ low_limit: 5
190
+ address: 302 Sharon Ave SW
191
+ url: https://goo.gl/maps/JENurv2NNhDrk6Mu6
172
192
  - name: Societe Coffee Lounge
173
193
  high_limit: -3
174
194
  address: 1223 11 Ave SW
175
195
  rainy_day: true
176
- paused: true
177
196
  - name: Sought X Found Coffee
178
197
  url: https://www.soughtxfound.coffee
179
198
  high_limit: -3
180
199
  address: 916 Centre Street North
181
200
  rainy_day: true
182
- paused: true
201
+ paused: true # Opens 8:30AM as of 2022-11-17
202
+ - name: Muze Coffeehouse
203
+ url: TODO
204
+ high_limit: -3
205
+ address: TODO
206
+ rainy_day: true
207
+ paused: true # "temporarily closed" in Google as of 2022-11-17
183
208
  - low_limit: 10
184
209
  url: http://www.calgary.ca/CSPS/Parks/Pages/Locations/SW-parks/Stanley-Park.aspx
185
210
  name: Stanley Park Flower Garden
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coffeeoutside
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Crosby
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-12 00:00:00.000000000 Z
11
+ date: 2023-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: icalendar
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - '='
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.2.7
55
- - !ruby/object:Gem::Dependency
56
- name: twitter
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - '='
60
- - !ruby/object:Gem::Version
61
- version: 7.0.0
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - '='
67
- - !ruby/object:Gem::Version
68
- version: 7.0.0
69
55
  description: The CoffeeOutside bot helps choose a coffee location based on weather
70
56
  and other inputs
71
57
  email:
@@ -73,7 +59,9 @@ executables: []
73
59
  extensions: []
74
60
  extra_rdoc_files: []
75
61
  files:
62
+ - ".github/workflows/ruby.yaml"
76
63
  - ".gitignore"
64
+ - ".rubocop.yml"
77
65
  - CODE_OF_CONDUCT.md
78
66
  - Gemfile
79
67
  - Guardfile
@@ -91,7 +79,7 @@ files:
91
79
  - lib/coffeeoutside/dispatchers/json.rb
92
80
  - lib/coffeeoutside/dispatchers/rss.rb
93
81
  - lib/coffeeoutside/dispatchers/stdout.rb
94
- - lib/coffeeoutside/dispatchers/twitter.rb
82
+ - lib/coffeeoutside/event_time.rb
95
83
  - lib/coffeeoutside/locations.rb
96
84
  - lib/coffeeoutside/version.rb
97
85
  - lib/coffeeoutside/weather.rb
@@ -106,6 +94,7 @@ metadata:
106
94
  allowed_push_host: https://rubygems.org
107
95
  homepage_uri: https://coffeeoutside.bike
108
96
  source_code_uri: https://github.com/yycbike/coffeeoutside
97
+ rubygems_mfa_required: 'true'
109
98
  post_install_message:
110
99
  rdoc_options: []
111
100
  require_paths:
@@ -121,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
110
  - !ruby/object:Gem::Version
122
111
  version: '0'
123
112
  requirements: []
124
- rubygems_version: 3.2.22
113
+ rubygems_version: 3.3.26
125
114
  signing_key:
126
115
  specification_version: 4
127
116
  summary: The CoffeeOutside bot
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: false
2
-
3
- require_relative 'dispatcher'
4
- require 'json'
5
- require 'twitter'
6
-
7
- module CoffeeOutside
8
- class TwitterDispatcher < DispatcherBase
9
- def notify_production
10
- # Configure client
11
- client = Twitter::REST::Client.new do |config|
12
- config.consumer_key = @params['consumer_key']
13
- config.consumer_secret = @params['consumer_secret']
14
- config.access_token = @params['token']
15
- config.access_token_secret = @params['token_secret']
16
- end
17
-
18
- # Send location tweet
19
- t = client.update location_tweet_msg
20
- # puts t
21
-
22
- # Send followup tweets
23
- # client.update('test', { in_reply_to_status_id: t.id }) if t.id
24
- end
25
-
26
- def notify_debug
27
- puts "consumer_key = #{@params['consumer_key']}"
28
- puts "consumer_secret = #{@params['consumer_secret']}"
29
- puts "access_token = #{@params['token']}"
30
- puts "access_token_secret = #{@params['token_secret']}"
31
- puts location_tweet_msg
32
- puts "\n"
33
- end
34
-
35
- def location_tweet_msg
36
- str = "This week's #CoffeeOutside: #{@location.name}"
37
- str << " #{@location.url}" if @location.url
38
- str << " (#{@location.address})" if @location.address
39
- str << ', see you there! #yycbike'
40
- str
41
- end
42
-
43
- def weather_tweet_msg
44
- # TODO
45
- end
46
-
47
- def nearby_locations_tweet_msg
48
- # TODO
49
- end
50
- end
51
- end