coffeeoutside 0.2.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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