meetupinator 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|