meetupinator 0.4 → 0.5
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 +4 -4
- data/README.md +2 -8
- data/lib/meetupinator/app.rb +25 -0
- data/lib/meetupinator/cli.rb +45 -0
- data/lib/meetupinator/event_finder.rb +10 -0
- data/lib/meetupinator/event_list_file_writer.rb +50 -0
- data/lib/meetupinator/input_file_reader.rb +12 -0
- data/lib/meetupinator/meetup_api.rb +73 -0
- data/lib/meetupinator/version.rb +4 -0
- data/lib/meetupinator.rb +7 -0
- data/spec/fixtures/functional.csv +22 -0
- data/spec/functional/cli_spec.rb +38 -0
- data/spec/lib/meetupinator/app_spec.rb +35 -0
- data/spec/lib/meetupinator/event_finder_spec.rb +29 -0
- data/spec/lib/meetupinator/event_list_file_writer_spec.rb +77 -0
- data/spec/lib/meetupinator/functional_spec.rb +116 -0
- data/spec/lib/meetupinator/input_file_reader_spec.rb +23 -0
- data/spec/lib/meetupinator/meetup_api_spec.rb +78 -0
- data/spec/test_helpers/match_stdout.rb +32 -0
- data/spec/vcr_cassettes/events_multiple_groups.yml +2059 -0
- data/spec/vcr_cassettes/events_next_week.yml +111 -0
- data/spec/vcr_cassettes/events_single_group.yml +305 -0
- data/spec/vcr_cassettes/functional.yml +989 -0
- data/spec/vcr_cassettes/getevents_functional_test.yml +532 -0
- data/spec/vcr_cassettes/groups.yml +112 -0
- metadata +40 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 807cb86ec05130fef1235a08122c6a80f7475699
|
4
|
+
data.tar.gz: 532b7089fc9b8c295dbb33ef5390a8cdcdc0ca49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ef813072e22cd0c8f9818730a6b6e7e8d186a638d1b369498d79de625104aa1094377dca543ca874537a1ebab1a896a24925977c4e034d2faa55f5b80db3bef
|
7
|
+
data.tar.gz: f311fc3c830f103787d7c72bde26a2681787bd524838621a6172a5af2a1a3baa31260d7e489e85bd01c4013faa7151bb348e13ceaa8e90c460c86c4aa394097f
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ This will write a otuput.csv to the current directory.
|
|
22
22
|
## During development
|
23
23
|
|
24
24
|
```
|
25
|
-
$
|
25
|
+
$ bundle exec ./bin/meetupinator ...
|
26
26
|
```
|
27
27
|
|
28
28
|
# todo
|
@@ -30,11 +30,5 @@ $ ruby -Ilib ./bin/meetupinator ...
|
|
30
30
|
- [ ] - provide options for date range
|
31
31
|
- [x] - Gem this
|
32
32
|
|
33
|
-
##Spec Notes
|
34
|
-
- Using VCR gem, will call API when tests are run first time.
|
35
|
-
- Export MEETUP_API_KEY into your environment
|
36
|
-
- Times from the api are milliseconds since epoch
|
37
|
-
|
38
|
-
|
39
33
|
# Licence
|
40
|
-
|
34
|
+
[MIT](https://github.com/joesustaric/meetupinator/blob/master/LICENSE.md)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Meetupinator
|
2
|
+
# doco
|
3
|
+
class App
|
4
|
+
def self.version
|
5
|
+
'meetupinator v' + Meetupinator::VERSION
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.run(args = {})
|
9
|
+
new.run(args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run(args)
|
13
|
+
init(args)
|
14
|
+
events = @event_finder.extract_events(@group_names, @api, args[:week])
|
15
|
+
@event_list_file_writer.write events, args[:output]
|
16
|
+
end
|
17
|
+
|
18
|
+
def init(args)
|
19
|
+
@api = Meetupinator::MeetupAPI.new(args[:meetup_api_key])
|
20
|
+
@group_names = Meetupinator::InputFileReader.group_names args[:input]
|
21
|
+
@event_finder = Meetupinator::EventFinder.new
|
22
|
+
@event_list_file_writer = Meetupinator::EventListFileWriter.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'meetupinator'
|
3
|
+
|
4
|
+
module Meetupinator
|
5
|
+
# class doco
|
6
|
+
# rubocop:disable Metrics/LineLength
|
7
|
+
class CLI < Thor
|
8
|
+
attr_accessor :event_finder
|
9
|
+
attr_accessor :event_list_file_writer
|
10
|
+
attr_accessor :api
|
11
|
+
|
12
|
+
class_option :meetup_api_key,
|
13
|
+
type: :string, aliases: '-k',
|
14
|
+
desc: 'API key for the meetup.com API,
|
15
|
+
defaults to MEETUP_API_KEY environment
|
16
|
+
variable if not set'
|
17
|
+
|
18
|
+
desc 'getevents', 'Write all upcoming events for the given meetup
|
19
|
+
groups specified in INPUT to OUTPUT'
|
20
|
+
map 'getevents' => 'run_app'
|
21
|
+
method_option :input, aliases: '-i', required: true, type: :string,
|
22
|
+
desc: 'The location of the input file'
|
23
|
+
method_option :output,
|
24
|
+
aliases: '-o', required: false, type: :string,
|
25
|
+
default: 'output.csv',
|
26
|
+
desc: 'The name of the file you want to output. (default is ./output.csv)'
|
27
|
+
|
28
|
+
method_option :week, aliases: '-w', required: false, type: :boolean
|
29
|
+
|
30
|
+
def run_app
|
31
|
+
Meetupinator::App.run(options)
|
32
|
+
puts "Output written to #{options[:output]}"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc '--version', 'Print version'
|
36
|
+
map '--version' => 'version'
|
37
|
+
map '-v' => 'version'
|
38
|
+
def version
|
39
|
+
puts Meetupinator::App.version
|
40
|
+
end
|
41
|
+
|
42
|
+
default_task :run_app
|
43
|
+
end
|
44
|
+
end
|
45
|
+
# rubocop:enable Metrics/LineLength
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module Meetupinator
|
4
|
+
# class def
|
5
|
+
class EventListFileWriter
|
6
|
+
def write(events, file_name)
|
7
|
+
CSV.open(file_name, 'wb') do |csv|
|
8
|
+
csv << ['Group name', 'Event name', 'Day of week', 'Date',
|
9
|
+
'Start time', 'End time', 'Event URL']
|
10
|
+
events.each do |event|
|
11
|
+
csv << extract_row(event)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def extract_row(event)
|
19
|
+
start_time, end_time = extract_times event
|
20
|
+
[
|
21
|
+
event['group']['name'], event['name'], start_time.strftime('%A'),
|
22
|
+
start_time.strftime('%-e/%m/%Y'), start_time.strftime('%-l:%M %p'),
|
23
|
+
end_time.strftime('%-l:%M %p'), event['event_url']
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
def extract_times(event)
|
28
|
+
start_time = time_with_offset(event['time'], event['utc_offset'])
|
29
|
+
# According to http://www.meetup.com/meetup_api/docs/2/events/,
|
30
|
+
# if no duration is specified, we can assume 3 hours.
|
31
|
+
# TODO: We should probably display a warning when this happens.
|
32
|
+
duration = event['duration'] || three_hours
|
33
|
+
end_time = start_time + ms_to_seconds(duration)
|
34
|
+
|
35
|
+
[start_time, end_time]
|
36
|
+
end
|
37
|
+
|
38
|
+
def time_with_offset(time, offset)
|
39
|
+
Time.at(ms_to_seconds(time)).getlocal(ms_to_seconds(offset))
|
40
|
+
end
|
41
|
+
|
42
|
+
def ms_to_seconds(ms)
|
43
|
+
ms / 1000
|
44
|
+
end
|
45
|
+
|
46
|
+
def three_hours
|
47
|
+
3 * 60 * 60 * 1000
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Meetupinator
|
5
|
+
# This class is responsible for communicating with the meetup.com API
|
6
|
+
# and returning the json responses only.
|
7
|
+
class MeetupAPI
|
8
|
+
attr_reader :api_key
|
9
|
+
|
10
|
+
def initialize(api_key = nil)
|
11
|
+
@base_uri = 'api.meetup.com'
|
12
|
+
@groups_endpoint = '/2/groups'
|
13
|
+
@events_endpoint = '/2/events'
|
14
|
+
if key_valid?(api_key) || key_found_in_env?
|
15
|
+
@api_key = retreive_key api_key
|
16
|
+
else
|
17
|
+
fail('no MEETUP_API_KEY provided')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_meetup_id(group_url_name)
|
22
|
+
query_string = 'key=' + @api_key + '&group_urlname=' + group_url_name
|
23
|
+
uri = URI::HTTP.build(host: @base_uri, path: @groups_endpoint,
|
24
|
+
query: query_string)
|
25
|
+
extract_meetup_id get_meetup_response(uri)
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_upcoming_events(group_ids, week)
|
29
|
+
query_string = 'sign=true&photo-host=public&status=upcoming&key=' +
|
30
|
+
@api_key + '&group_id=' + group_ids.join(',')
|
31
|
+
|
32
|
+
query_string << '&time=,1w' if week
|
33
|
+
|
34
|
+
uri = URI::HTTP.build(host: @base_uri, path: @events_endpoint,
|
35
|
+
query: query_string)
|
36
|
+
response = get_meetup_response uri
|
37
|
+
get_results response
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def get_meetup_response(uri)
|
43
|
+
response = Net::HTTP.get_response uri
|
44
|
+
if response.code != '200'
|
45
|
+
msg = "Call to #{uri} failed: #{response.code} - #{response.message}"
|
46
|
+
msg << '. ' + response.body if response.class.body_permitted?
|
47
|
+
fail(msg)
|
48
|
+
end
|
49
|
+
JSON.parse response.body
|
50
|
+
end
|
51
|
+
|
52
|
+
def extract_meetup_id(response)
|
53
|
+
get_results(response)[0]['id']
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_results(response)
|
57
|
+
response['results']
|
58
|
+
end
|
59
|
+
|
60
|
+
def retreive_key(api_key)
|
61
|
+
return api_key if key_valid? api_key
|
62
|
+
return ENV['MEETUP_API_KEY'] if key_found_in_env?
|
63
|
+
end
|
64
|
+
|
65
|
+
def key_valid?(api_key)
|
66
|
+
!(api_key.nil? || api_key.empty?)
|
67
|
+
end
|
68
|
+
|
69
|
+
def key_found_in_env?
|
70
|
+
!(ENV['MEETUP_API_KEY'].nil? || ENV['MEETUP_API_KEY'].empty?)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/meetupinator.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Group name,Event name,Day of week,Date,Start time,End time,Event URL
|
2
|
+
Ruby and Rails Melbourne,Ruby on Rails InstallFest,Thursday,19/02/2015,6:30 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/219051382/
|
3
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,25/02/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/219387830/
|
4
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,10/03/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/219525271/
|
5
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,25/03/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/219525272/
|
6
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,14/04/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/tdxfdlytgbsb/
|
7
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,29/04/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/fdxfdlytgbmc/
|
8
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,12/05/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/tdxfdlythbqb/
|
9
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,27/05/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/fdxfdlythbkc/
|
10
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,9/06/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/220405387/
|
11
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,24/06/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/fdxfdlytjbgc/
|
12
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,14/07/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/tdxfdlytkbsb/
|
13
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,29/07/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/fdxfdlytkbmc/
|
14
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,11/08/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/tdxfdlytlbpb/
|
15
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,26/08/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/fdxfdlytlbjc/
|
16
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,8/09/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/tdxfdlytmblb/
|
17
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,30/09/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/fdxfdlytmbnc/
|
18
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,13/10/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/tdxfdlytnbrb/
|
19
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,28/10/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/fdxfdlytnblc/
|
20
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,10/11/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/tdxfdlytpbnb/
|
21
|
+
Ruby and Rails Melbourne,Melbourne Ruby,Wednesday,25/11/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/fdxfdlytpbhc/
|
22
|
+
Ruby and Rails Melbourne,Hack Night,Tuesday,8/12/2015,6:00 PM,9:00 PM,http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/tdxfdlytqblb/
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'vcr_setup'
|
3
|
+
require 'meetupinator/cli'
|
4
|
+
|
5
|
+
# I wanted to execute these tests by running the exe file
|
6
|
+
# but it won't engage the vcr gem because I think it might
|
7
|
+
# spawn a new process? (I think)
|
8
|
+
describe 'The meetupinator command line interface' do
|
9
|
+
let(:meetups) { ['MelbNodeJS', 'Ruby-On-Rails-Oceania-Melbourne'] }
|
10
|
+
|
11
|
+
before do
|
12
|
+
FileUtils.mkdir_p('test')
|
13
|
+
Dir.chdir('test')
|
14
|
+
File.open('input.txt', 'wb') do |file|
|
15
|
+
meetups.each { |m| file << m + "\n" }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
Dir.chdir('..')
|
21
|
+
FileUtils.rm_rf('test')
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'no arguments' do
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'meetup api and input file specified' do
|
28
|
+
it 'generates the correct output.csv in the working dir' do
|
29
|
+
VCR.use_cassette('functional') do
|
30
|
+
Meetupinator::CLI.start(['-i', 'input.txt', '-k', '1234'])
|
31
|
+
end
|
32
|
+
expect(CSV.read('output.csv')).to eq(CSV.read('../spec/fixtures/functional.csv'))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'meetup api and input file and output file specified' do
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'fakefs/spec_helpers'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'meetupinator/app'
|
4
|
+
|
5
|
+
describe Meetupinator::App do
|
6
|
+
describe '#run' do
|
7
|
+
let(:input_file) { 'input.txt' }
|
8
|
+
let(:output_file) { 'output.csv' }
|
9
|
+
let(:event_finder) { double('event finder') }
|
10
|
+
let(:file_writer) { double('file writer') }
|
11
|
+
let(:meetup_api) { double('meetup api') }
|
12
|
+
let(:group_names) { ['First meetup group', 'Second meetup group'] }
|
13
|
+
let(:events) { double('events') }
|
14
|
+
let(:args) do
|
15
|
+
{
|
16
|
+
meetup_api_key: 1234,
|
17
|
+
input: input_file,
|
18
|
+
output: output_file,
|
19
|
+
week: false
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when input file / output file / api key / is specified' do
|
24
|
+
it 'executes the program' do
|
25
|
+
expect(Meetupinator::MeetupAPI).to receive(:new).and_return(meetup_api)
|
26
|
+
expect(Meetupinator::InputFileReader).to receive(:group_names).with(input_file).and_return(group_names)
|
27
|
+
expect(Meetupinator::EventFinder).to receive(:new).and_return(event_finder)
|
28
|
+
expect(Meetupinator::EventListFileWriter).to receive(:new).and_return(file_writer)
|
29
|
+
expect(event_finder).to receive(:extract_events).with(group_names, meetup_api, false).and_return(events)
|
30
|
+
expect(file_writer).to receive(:write).with(events, output_file)
|
31
|
+
Meetupinator::App.run(args)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'meetupinator/event_finder'
|
3
|
+
require 'meetupinator/meetup_api'
|
4
|
+
|
5
|
+
describe Meetupinator::EventFinder do
|
6
|
+
describe '#extract_events' do
|
7
|
+
let(:meetups) do
|
8
|
+
{
|
9
|
+
'first' => 101,
|
10
|
+
'second' => 201,
|
11
|
+
'third' => 301
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:events) { [:first_event, :another_event, :more_events, :final_event] }
|
16
|
+
let(:events_in_week) { [:event_in_week] }
|
17
|
+
|
18
|
+
let(:api) { instance_double(Meetupinator::MeetupAPI) }
|
19
|
+
|
20
|
+
before do
|
21
|
+
allow(api).to receive(:get_meetup_id) { |name| meetups[name] }
|
22
|
+
allow(api).to receive(:get_upcoming_events).with(meetups.values, nil) { events }
|
23
|
+
allow(api).to receive(:get_upcoming_events).with(meetups.values, true) { events_in_week }
|
24
|
+
end
|
25
|
+
|
26
|
+
it { expect(subject.extract_events(meetups.keys, api, nil)).to eq(events) }
|
27
|
+
it { expect(subject.extract_events(meetups.keys, api, true)).to eq(events_in_week) }
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'fakefs/spec_helpers'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'meetupinator/event_list_file_writer'
|
4
|
+
|
5
|
+
describe Meetupinator::EventListFileWriter do
|
6
|
+
include FakeFS::SpecHelpers::All
|
7
|
+
|
8
|
+
let(:file_name) { 'output.csv' }
|
9
|
+
let(:events) do
|
10
|
+
[
|
11
|
+
{
|
12
|
+
'group' => { 'name' => 'The Society of Chocolate Eaters' },
|
13
|
+
'name' => 'The Time When We Eat Chocolate',
|
14
|
+
'time' => 142_355_160_000_0,
|
15
|
+
'utc_offset' => 396_000_00,
|
16
|
+
'duration' => 720_000_0,
|
17
|
+
'event_url' => 'http://www.awesomemeetup.com/'
|
18
|
+
}
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:expected_csv_output) do
|
23
|
+
[
|
24
|
+
{
|
25
|
+
group_name: 'The Society of Chocolate Eaters',
|
26
|
+
event_name: 'The Time When We Eat Chocolate',
|
27
|
+
day_of_week: 'Tuesday',
|
28
|
+
date: '10/02/2015',
|
29
|
+
start_time: '6:00 PM',
|
30
|
+
end_time: '8:00 PM',
|
31
|
+
event_url: 'http://www.awesomemeetup.com/'
|
32
|
+
}
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
def clean_up
|
37
|
+
File.delete(file_name) if File.exist?(file_name)
|
38
|
+
end
|
39
|
+
|
40
|
+
before { clean_up }
|
41
|
+
|
42
|
+
after { clean_up }
|
43
|
+
|
44
|
+
describe '#write' do
|
45
|
+
it 'writes the events to file' do
|
46
|
+
subject.write events, file_name
|
47
|
+
|
48
|
+
File.open file_name do |body|
|
49
|
+
csv = CSV.new(body, headers: true, header_converters: :symbol,
|
50
|
+
converters: :all)
|
51
|
+
actual_csv_output = csv.to_a.map(&:to_hash)
|
52
|
+
expect(actual_csv_output).to eq(expected_csv_output)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when the event does not have a duration' do
|
57
|
+
before do
|
58
|
+
events[0].delete('duration')
|
59
|
+
expected_csv_output[0][:end_time] = '9:00 PM'
|
60
|
+
end
|
61
|
+
|
62
|
+
# According to http://www.meetup.com/meetup_api/docs/2/events/,
|
63
|
+
# if no duration is specified,
|
64
|
+
# we can assume 3 hours.
|
65
|
+
it 'writes the event to file assuming the duration is 3 hours' do
|
66
|
+
subject.write events, file_name
|
67
|
+
|
68
|
+
File.open file_name do |body|
|
69
|
+
csv = CSV.new(body, headers: true, header_converters: :symbol,
|
70
|
+
converters: :all)
|
71
|
+
actual_csv_output = csv.to_a.map(&:to_hash)
|
72
|
+
expect(actual_csv_output).to eq(expected_csv_output)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'vcr_setup'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'meetupinator/cli'
|
4
|
+
|
5
|
+
# Joe: I know I've written another functional test as well but,
|
6
|
+
# i'll leave this one in here too.
|
7
|
+
# Sometime it helps to write the output to disk especially for debugging.
|
8
|
+
|
9
|
+
describe 'meetupinator' do
|
10
|
+
# In an ideal world, we'd use FakeFS here.
|
11
|
+
# Unfortunately, FakeFS and VCR don't coexist very well.
|
12
|
+
# Something like the solution proposed in https://github.com/vcr/vcr/issues/234 could work,
|
13
|
+
# but for the time being we can just use temp files instead.
|
14
|
+
let(:input_file) { Dir::Tmpname.make_tmpname(['input', '.txt'], nil) }
|
15
|
+
let(:output_file) { Dir::Tmpname.make_tmpname(['output', '.csv'], nil) }
|
16
|
+
|
17
|
+
let(:expected_csv_output) do
|
18
|
+
[
|
19
|
+
{
|
20
|
+
group_name: 'The Melbourne Node.JS Meetup Group',
|
21
|
+
event_name: 'Feb meetup: io.js & ES6 & more',
|
22
|
+
day_of_week: 'Wednesday',
|
23
|
+
date: '4/02/2015',
|
24
|
+
start_time: '6:30 PM',
|
25
|
+
end_time: '9:30 PM',
|
26
|
+
event_url: 'http://www.meetup.com/MelbNodeJS/events/219976432/'
|
27
|
+
},
|
28
|
+
{
|
29
|
+
group_name: 'Ruby and Rails Melbourne',
|
30
|
+
event_name: 'Hack Night',
|
31
|
+
day_of_week: 'Tuesday',
|
32
|
+
date: '10/02/2015',
|
33
|
+
start_time: '6:00 PM',
|
34
|
+
end_time: '9:00 PM',
|
35
|
+
event_url: 'http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/219387827/'
|
36
|
+
},
|
37
|
+
{
|
38
|
+
group_name: 'Ruby and Rails Melbourne',
|
39
|
+
event_name: 'Ruby on Rails InstallFest',
|
40
|
+
day_of_week: 'Thursday',
|
41
|
+
date: '19/02/2015',
|
42
|
+
start_time: '6:30 PM',
|
43
|
+
end_time: '9:00 PM',
|
44
|
+
event_url: 'http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/219051382/'
|
45
|
+
},
|
46
|
+
{
|
47
|
+
group_name: 'Ruby and Rails Melbourne',
|
48
|
+
event_name: 'Melbourne Ruby',
|
49
|
+
day_of_week: 'Wednesday',
|
50
|
+
date: '25/02/2015',
|
51
|
+
start_time: '6:00 PM',
|
52
|
+
end_time: '9:00 PM',
|
53
|
+
event_url: 'http://www.meetup.com/Ruby-On-Rails-Oceania-Melbourne/events/219387830/'
|
54
|
+
}
|
55
|
+
]
|
56
|
+
end
|
57
|
+
|
58
|
+
def clean_up(file)
|
59
|
+
File.delete(file) if File.exist?(file)
|
60
|
+
end
|
61
|
+
|
62
|
+
before do
|
63
|
+
clean_up input_file
|
64
|
+
clean_up output_file
|
65
|
+
create_input_file
|
66
|
+
end
|
67
|
+
|
68
|
+
after do
|
69
|
+
clean_up input_file
|
70
|
+
clean_up output_file
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when given minimal correct arguments' do
|
74
|
+
it 'will fetch and save events for all meetups' do
|
75
|
+
VCR.use_cassette('getevents_functional_test') do
|
76
|
+
args = ['getevents', '-i', input_file, '-o', output_file, '-k', '1234']
|
77
|
+
expect { Meetupinator::CLI.start(args) }.to match_stdout("Output written to #{output_file}")
|
78
|
+
expect(read_output_file).to eq(expected_csv_output)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when given the --version argument' do
|
84
|
+
before { stub_const('Meetupinator::VERSION', '9.23') }
|
85
|
+
|
86
|
+
it 'returns the version' do
|
87
|
+
args = ['--version']
|
88
|
+
expect { Meetupinator::CLI.start(args) }.to match_stdout('meetupinator v9.23')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when given the -v argument' do
|
93
|
+
before { stub_const('Meetupinator::VERSION', '9.23') }
|
94
|
+
|
95
|
+
it 'returns the version' do
|
96
|
+
args = ['-v']
|
97
|
+
expect { Meetupinator::CLI.start(args) }.to match_stdout('meetupinator v9.23')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def create_input_file
|
102
|
+
group_names = ['MelbNodeJS', 'Ruby-On-Rails-Oceania-Melbourne']
|
103
|
+
File.open(input_file, 'wb') do |file|
|
104
|
+
group_names.each { |name| file << name + "\n" }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def read_output_file
|
109
|
+
actual_csv_output = nil
|
110
|
+
File.open output_file do |body|
|
111
|
+
csv = CSV.new(body, headers: true, header_converters: :symbol, converters: :all)
|
112
|
+
actual_csv_output = csv.to_a.map(&:to_hash)
|
113
|
+
end
|
114
|
+
actual_csv_output
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'fakefs/spec_helpers'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'meetupinator/input_file_reader'
|
4
|
+
|
5
|
+
describe Meetupinator::InputFileReader do
|
6
|
+
include FakeFS::SpecHelpers::All
|
7
|
+
|
8
|
+
let(:input_file_dir) { '/tmp/input/file/location' }
|
9
|
+
let(:file_name) { input_file_dir + '/input_file.txt' }
|
10
|
+
let(:group_names) { %w(some_group another_group more_groups) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
# need to make dir for fakefs
|
14
|
+
FileUtils.mkdir_p(input_file_dir)
|
15
|
+
File.open(file_name, 'wb') do |file|
|
16
|
+
group_names.each { |items| file << items + "\n" }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#group_names' do
|
21
|
+
it { expect(Meetupinator::InputFileReader.group_names(file_name)).to eq(group_names) }
|
22
|
+
end
|
23
|
+
end
|