rMeetup 1.0 → 2.0.1

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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +21 -0
  3. data/README.md +65 -0
  4. data/Rakefile +6 -12
  5. data/lib/core_ext/string.rb +11 -0
  6. data/lib/rmeetup.rb +2 -63
  7. data/lib/rmeetup/client.rb +77 -0
  8. data/lib/rmeetup/errors.rb +15 -0
  9. data/lib/rmeetup/fetcher.rb +20 -33
  10. data/lib/rmeetup/fetcher/base.rb +66 -55
  11. data/lib/rmeetup/fetcher/open_events.rb +14 -0
  12. data/lib/rmeetup/fetcher/venues.rb +14 -0
  13. data/lib/rmeetup/poster.rb +17 -0
  14. data/lib/rmeetup/poster/base.rb +81 -0
  15. data/lib/rmeetup/{fetcher/comments.rb → poster/event_comment.rb} +5 -5
  16. data/lib/rmeetup/type.rb +2 -1
  17. data/lib/rmeetup/type/event.rb +21 -18
  18. data/lib/rmeetup/type/event_comment.rb +42 -0
  19. data/lib/rmeetup/type/rsvp.rb +9 -5
  20. data/lib/rmeetup/type/venue.rb +63 -0
  21. data/lib/rmeetup/version.rb +14 -0
  22. data/rmeetup.gemspec +34 -0
  23. data/spec/client_spec.rb +77 -29
  24. data/spec/fetcher_spec.rb +4 -4
  25. data/spec/fixtures/vcr_cassettes/fetching_cities.yml +358 -0
  26. data/spec/fixtures/vcr_cassettes/fetching_events.yml +54 -0
  27. data/spec/fixtures/vcr_cassettes/fetching_groups.yml +8627 -0
  28. data/spec/fixtures/vcr_cassettes/fetching_members.yml +3984 -0
  29. data/spec/fixtures/vcr_cassettes/fetching_photos.yml +54 -0
  30. data/spec/fixtures/vcr_cassettes/fetching_rsvps.yml +54 -0
  31. data/spec/spec_helper.rb +11 -69
  32. metadata +140 -101
  33. data/Manifest +0 -45
  34. data/README.rdoc +0 -34
  35. data/lib/rmeetup/fetcher/topics.rb +0 -14
  36. data/rMeetup.gemspec +0 -29
  37. data/spec/fetchers/base_spec.rb +0 -58
  38. data/spec/fetchers/cities_spec.rb +0 -18
  39. data/spec/fetchers/comments_spec.rb +0 -14
  40. data/spec/fetchers/events_spec.rb +0 -14
  41. data/spec/fetchers/groups_spec.rb +0 -14
  42. data/spec/fetchers/members_spec.rb +0 -14
  43. data/spec/fetchers/photos_spec.rb +0 -14
  44. data/spec/fetchers/rsvps_spec.rb +0 -14
  45. data/spec/fetchers/topics_spec.rb +0 -14
  46. data/spec/responses/cities.json +0 -1
  47. data/spec/responses/comments.json +0 -1
  48. data/spec/responses/error.json +0 -1
  49. data/spec/responses/events.json +0 -1
  50. data/spec/responses/groups.json +0 -1
  51. data/spec/responses/members.json +0 -1
  52. data/spec/responses/photos.json +0 -1
  53. data/spec/responses/rsvps.json +0 -1
  54. data/spec/responses/topics.json +0 -1
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class OpenEvents < Base
4
+ def initialize
5
+ @type = :open_events
6
+ end
7
+
8
+ # Turn the result hash into a Event Class
9
+ def format_result(result)
10
+ RMeetup::Type::Event.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class Venues < Base
4
+ def initialize
5
+ @type = :venues
6
+ end
7
+
8
+ # Turn the result hash into a Venue Class
9
+ def format_result(result)
10
+ RMeetup::Type::Venue.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require "rmeetup/poster/base"
2
+ require "rmeetup/poster/event_comment"
3
+
4
+ module RMeetup
5
+ module Poster
6
+
7
+ def self.for(type)
8
+ name = type.to_s.camel_case.to_sym
9
+ if (name && constants.include?(name))
10
+ const_get(name).new
11
+ else
12
+ raise InvalidRequestTypeError.new(type)
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,81 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+
4
+ module RMeetup
5
+ module Poster
6
+ class ApiError < StandardError
7
+ def initialize(error_message, request_url)
8
+ super "Meetup API Error: #{error_message} - API URL: #{request_url}"
9
+ end
10
+ end
11
+
12
+ class NoResponseError < StandardError
13
+ def initialize
14
+ super "No Response was returned from the Meetup API."
15
+ end
16
+ end
17
+
18
+ # == RMeetup::Fetcher::Base
19
+ #
20
+ # Base fetcher class that other fetchers
21
+ # will inherit from.
22
+ class Base
23
+ def initialize
24
+ @type = nil
25
+ end
26
+
27
+ # Fetch and parse a response
28
+ # based on a set of options.
29
+ # Override this method to ensure
30
+ # neccessary options are passed
31
+ # for the request.
32
+ def post(options = {})
33
+ url = build_url(options)
34
+ ret = post_response(url, options)
35
+ ret
36
+ end
37
+
38
+ protected
39
+ # OVERRIDE this method to format a result section
40
+ # as per Result type.
41
+ # Takes a result in a collection and
42
+ # formats it to be put back into the collection.
43
+ def format_result(result)
44
+ result
45
+ end
46
+
47
+ def build_url(options)
48
+ base_url
49
+ end
50
+
51
+ def base_url
52
+ "https://api.meetup.com/2/#{@type}/"
53
+ end
54
+
55
+ # Create a query string from an options hash
56
+ def params_for(options)
57
+ params = []
58
+ options.each do |key, value|
59
+ params << "#{key}=#{value}"
60
+ end
61
+ "?#{params.join("&")}"
62
+ end
63
+
64
+ # Encode a hash of options to be used as request parameters
65
+ def encode_options(options)
66
+ options.each do |key,value|
67
+ options[key] = URI.encode(value.to_s)
68
+ end
69
+ end
70
+
71
+ def post_response(url, options)
72
+ sslurl = URI.parse(url)
73
+ https = Net::HTTP.new(sslurl.host, sslurl.port)
74
+ https.use_ssl = true
75
+ req = Net::HTTP::Post.new(sslurl.path)
76
+ req.set_form_data(options)
77
+ resp = https.request(req)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,14 +1,14 @@
1
1
  module RMeetup
2
- module Fetcher
3
- class Comments < Base
2
+ module Poster
3
+ class EventComment < Base
4
4
  def initialize
5
- @type = :comments
5
+ @type = :event_comment
6
6
  end
7
7
 
8
8
  # Turn the result hash into a Comment Class
9
9
  def format_result(result)
10
- RMeetup::Type::Comment.new(result)
10
+ RMeetup::Type::EventComment.new(result)
11
11
  end
12
12
  end
13
13
  end
14
- end
14
+ end
@@ -5,4 +5,5 @@ require "rmeetup/type/member"
5
5
  require "rmeetup/type/rsvp"
6
6
  require "rmeetup/type/event"
7
7
  require "rmeetup/type/comment"
8
- require "rmeetup/type/photo"
8
+ require "rmeetup/type/photo"
9
+ require "rmeetup/type/venue"
@@ -1,47 +1,50 @@
1
1
  module RMeetup
2
2
  module Type
3
-
3
+
4
4
  # == RMeetup::Type::Event
5
5
  #
6
6
  # Data wraper for a Event fethcing response
7
7
  # Used to access result attributes as well
8
8
  # as progammatically fetch relative data types
9
9
  # based on this event.
10
-
11
- # Edited by Jason Berlinsky on 1/20/11 to allow for arbitrary data access
12
- # See http://www.meetup.com/meetup_api/docs/events/ for available fields
13
-
10
+
14
11
  class Event
15
-
16
- attr_accessor :event
17
-
18
12
  def initialize(event = {})
19
- self.event = event
13
+ @event = event
20
14
  end
21
-
15
+ attr_reader :event
16
+ alias_method :to_h, :event
17
+
22
18
  def method_missing(id, *args)
23
- return self.event[id.id2name]
19
+ if event.has_key?(id.id2name)
20
+ event[id.id2name]
21
+ else
22
+ fail NoMethodError.new('no method')
23
+ end
24
24
  end
25
-
25
+
26
26
  # Special accessors that need typecasting or other parsing
27
27
  def id
28
- self.event['id'].to_i
28
+ event['id'].to_i
29
29
  end
30
30
  def lat
31
- self.event['lat'].to_f
31
+ event['lat'].to_f
32
32
  end
33
33
  def lon
34
- self.event['lon'].to_f
34
+ event['lon'].to_f
35
35
  end
36
36
  def rsvpcount
37
- self.event['rsvpcount'].to_i
37
+ event['rsvpcount'].to_i
38
38
  end
39
39
  def updated
40
40
  DateTime.parse(self.event['updated'])
41
41
  end
42
42
  def time
43
- DateTime.parse(self.event['time'])
43
+ Time.at(self.event['time']/1000).to_datetime
44
+ end
45
+ def venue
46
+ OpenStruct.new( self.event['venue'] )
44
47
  end
45
48
  end
46
49
  end
47
- end
50
+ end
@@ -0,0 +1,42 @@
1
+ module RMeetup
2
+ module Type
3
+
4
+ # == RMeetup::Type::Comment
5
+ #
6
+ # Data wraper for a Comment fethcing response
7
+ # Used to access result attributes as well
8
+ # as progammatically fetch relative data types
9
+ # based on this comment.
10
+
11
+ # Edited by Jason Berlinsky on 1/20/11 to allow for arbitrary data access
12
+ # See http://www.meetup.com/meetup_api/docs/ew/comment/ for available fields
13
+
14
+ class EventComment
15
+
16
+ attr_accessor :comment
17
+
18
+ def initialize(comment = {})
19
+ self.comment = comment
20
+ end
21
+
22
+ def method_missing(id, *args)
23
+ return self.comment[id.id2name]
24
+ end
25
+
26
+ # Special accessors that need typecasting or other parsing
27
+
28
+ def rating
29
+ return self.comment['rating'].to_i
30
+ end
31
+ def created
32
+ return DateTime.parse(self.comment['created'])
33
+ end
34
+ def lat
35
+ return self.comment['lat'].to_f
36
+ end
37
+ def lon
38
+ return self.comment['lon'].to_f
39
+ end
40
+ end
41
+ end
42
+ end
@@ -12,14 +12,18 @@ module RMeetup
12
12
  # See http://www.meetup.com/meetup_api/docs/ew/rsvps/ for available fields
13
13
 
14
14
  class Rsvp
15
- attr_accessor :rsvp
16
-
17
15
  def initialize(rsvp = {})
18
- self.rsvp = rsvp
16
+ @rsvp = rsvp
19
17
  end
18
+ attr_accessor :rsvp
19
+ alias_method :to_h, :rsvp
20
20
 
21
21
  def method_missing(id, *args)
22
- return self.rsvp[id.id2name]
22
+ if rsvp.has_key?(id.id2name)
23
+ rsvp[id.id2name]
24
+ else
25
+ fail NoMethodError.new('no method')
26
+ end
23
27
  end
24
28
 
25
29
  # Special accessors that need typecasting or other parsing
@@ -32,4 +36,4 @@ module RMeetup
32
36
  end
33
37
  end
34
38
  end
35
- end
39
+ end
@@ -0,0 +1,63 @@
1
+ module RMeetup
2
+ module Type
3
+
4
+ # == RMeetup::Type::City
5
+ #
6
+ # Data wraper for a City fethcing response
7
+ # Used to access result attributes as well
8
+ # as progammatically fetch relative data types
9
+ # based on this city.
10
+
11
+ # Edited by Jason Berlinsky on 1/20/11 to allow for arbitrary data access
12
+ # See http://www.meetup.com/meetup_api/docs/cities/ for available fields
13
+
14
+ class Venue
15
+
16
+ attr_accessor :venue
17
+
18
+ def initialize(venue = {})
19
+ self.venue = venue
20
+ end
21
+
22
+ def method_missing(id, *args)
23
+ return self.venue[id.id2name]
24
+ end
25
+
26
+ # Special accessors that need typecasting or other parsing
27
+
28
+ def id
29
+ return self.venue['id'].to_i
30
+ end
31
+ def zip
32
+ return self.venue['zip'].to_s
33
+ end
34
+ def state
35
+ return self.venue['state'].to_s
36
+ end
37
+ def address_1
38
+ return self.venue['address_1'].to_s
39
+ end
40
+ def city
41
+ return self.venue['city'].to_s
42
+ end
43
+ def country
44
+ return self.venue['country'].to_s
45
+ end
46
+ def distance
47
+ return self.venue['distance'].to_i
48
+ end
49
+ def rating_count
50
+ return self.venue['rating_count'].to_i
51
+ end
52
+ def rating
53
+ return self.venue['rating'].to_s
54
+ end
55
+ def lat
56
+ return self.venue['lat'].to_f
57
+ end
58
+ def lon
59
+ return self.venue['lon'].to_f
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ class Version
3
+ MAJOR = 2
4
+ MINOR = 0
5
+ PATCH = 1
6
+ PRE = nil
7
+
8
+ class << self
9
+ def to_s
10
+ [MAJOR, MINOR, PATCH, PRE].compact.join('.')
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+ require 'rmeetup/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.platform = Gem::Platform::RUBY
8
+
9
+ spec.name = 'rMeetup'
10
+ spec.description = 'meetup.com ruby client lib'
11
+ spec.authors = ['Jared Pace', 'Jason Berlinsky', 'Tommy Chan', 'Tanner Mares', 'Zishan Ahmad', 'Nikica Jokić']
12
+ spec.email = ['jdpace@github.com', 'jason@jasonberlinsky.com', 'tommytcchan@gmail.com', 'tannermares@gmail.com', 'me@zishanahmad.com', 'neektza@gmail.com']
13
+ spec.homepage = 'https://github.com/neektza/rmeetup'
14
+ spec.summary = 'A Ruby wrapper for the Meetup REST API v2'
15
+
16
+ spec.required_rubygems_version = '>= 1.3.6'
17
+
18
+ spec.add_dependency 'json', '~> 1.8'
19
+ spec.add_dependency 'buftok', '~> 0.2'
20
+ spec.add_dependency 'http', '~> 0.6'
21
+ spec.add_dependency 'http_parser.rb', '~> 0.6'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.6'
24
+
25
+ spec.files = %w[LICENSE.md README.md Rakefile rmeetup.gemspec]
26
+ spec.licenses = %w[MIT]
27
+ spec.files += Dir.glob('lib/**/*.rb')
28
+ spec.files += Dir.glob('spec/**/*')
29
+
30
+ spec.test_files = Dir.glob('spec/**/*')
31
+ spec.require_paths = %w[lib]
32
+
33
+ spec.version = RMeetup::Version
34
+ end
@@ -1,35 +1,83 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe RMeetup::Client, 'trying to access the API before being configured' do
4
- it 'should throw an error trying to search' do
5
- lambda {
6
- RMeetup::Client.fetch(:topics)
7
- }.should raise_error(RMeetup::NotConfiguredError)
8
- end
9
- end
3
+ describe RMeetup::Client do
10
4
 
11
- describe RMeetup::Client, 'trying to fetch an unknown type' do
12
- before do
13
- RMeetup::Client.api_key = API_KEY
5
+ context 'provided no API key' do
6
+ it 'fails with an NotConfiguredError' do
7
+ expect { RMeetup::Client.new }.to raise_error(RMeetup::Error::NotConfiguredError)
8
+ end
14
9
  end
15
-
16
- it 'should throw an error' do
17
- lambda {
18
- RMeetup::Client.fetch(:clowns)
19
- }.should raise_error(RMeetup::InvalidRequestTypeError)
20
- end
21
- end
22
10
 
23
- describe RMeetup::Client, 'fetching some topics' do
24
- before do
25
- RMeetup::Client.api_key = API_KEY
26
- @topics_fetcher = mock(RMeetup::Fetcher::Topics)
27
- @topics_fetcher.stub!(:fetch).and_return([])
28
- @type = :topics
29
- end
30
-
31
- it 'should try to get a Topic Fetcher' do
32
- RMeetup::Fetcher.should_receive(:for).with(@type).and_return(@topics_fetcher)
33
- RMeetup::Client.fetch(@type,{})
11
+ context 'provided with proper options' do
12
+
13
+ describe "#fetch" do
14
+ let(:client) { RMeetup::Client.new({api_key: API_KEY}) }
15
+
16
+ it 'should throw an error if invalid data type is requested' do
17
+ expect do
18
+ client.fetch(:clowns)
19
+ end.to raise_error(RMeetup::Error::InvalidRequestTypeError)
20
+ end
21
+
22
+ context 'when fetching :groups' do
23
+ it 'returns a collection of Groups' do
24
+ VCR.use_cassette('fetching_groups') do
25
+ client.fetch(:groups, { topic: 'Ruby' }).each do |result|
26
+ result.should be_kind_of(RMeetup::Type::Group)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ context 'when fetching :events' do
33
+ it 'returns a collection of Events' do
34
+ VCR.use_cassette('fetching_events') do
35
+ client.fetch(:events, { group_id: '95875' }).each do |result|
36
+ result.should be_kind_of(RMeetup::Type::Event)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ context 'when fetching :rsvps' do
43
+ it 'returns a collection of RSVPs' do
44
+ VCR.use_cassette('fetching_rsvps') do
45
+ client.fetch(:rsvps, { event_id: '1342342' }).each do |result|
46
+ result.should be_kind_of(RMeetup::Type::Rsvp)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'when fetching :members' do
53
+ it 'returns a collection of Members' do
54
+ VCR.use_cassette('fetching_members') do
55
+ client.fetch(:members, { group_id: '95875' }).each do |result|
56
+ result.should be_kind_of(RMeetup::Type::Member)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ context 'when fetching :photos' do
63
+ it 'returns a collection of Photos' do
64
+ VCR.use_cassette('fetching_photos') do
65
+ client.fetch(:photos, { event_id: '13452536' }).each do |result|
66
+ result.should be_kind_of(RMeetup::Type::Photo)
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ context 'when fetching :cities' do
73
+ it 'returns a collection of Cities' do
74
+ VCR.use_cassette('fetching_cities') do
75
+ client.fetch(:cities).each do |result|
76
+ result.should be_kind_of(RMeetup::Type::City)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
34
82
  end
35
- end
83
+ end