rMeetup 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Manifest +45 -0
  2. data/README.rdoc +34 -0
  3. data/Rakefile +14 -0
  4. data/lib/rmeetup/collection.rb +58 -0
  5. data/lib/rmeetup/fetcher/base.rb +84 -0
  6. data/lib/rmeetup/fetcher/cities.rb +14 -0
  7. data/lib/rmeetup/fetcher/comments.rb +14 -0
  8. data/lib/rmeetup/fetcher/events.rb +14 -0
  9. data/lib/rmeetup/fetcher/groups.rb +14 -0
  10. data/lib/rmeetup/fetcher/members.rb +14 -0
  11. data/lib/rmeetup/fetcher/photos.rb +14 -0
  12. data/lib/rmeetup/fetcher/rsvps.rb +14 -0
  13. data/lib/rmeetup/fetcher/topics.rb +14 -0
  14. data/lib/rmeetup/fetcher.rb +38 -0
  15. data/lib/rmeetup/type/city.rb +39 -0
  16. data/lib/rmeetup/type/comment.rb +42 -0
  17. data/lib/rmeetup/type/event.rb +47 -0
  18. data/lib/rmeetup/type/group.rb +47 -0
  19. data/lib/rmeetup/type/member.rb +38 -0
  20. data/lib/rmeetup/type/photo.rb +32 -0
  21. data/lib/rmeetup/type/rsvp.rb +35 -0
  22. data/lib/rmeetup/type/topic.rb +38 -0
  23. data/lib/rmeetup/type.rb +8 -0
  24. data/lib/rmeetup.rb +69 -0
  25. data/rMeetup.gemspec +29 -0
  26. data/spec/client_spec.rb +35 -0
  27. data/spec/fetcher_spec.rb +18 -0
  28. data/spec/fetchers/base_spec.rb +58 -0
  29. data/spec/fetchers/cities_spec.rb +18 -0
  30. data/spec/fetchers/comments_spec.rb +14 -0
  31. data/spec/fetchers/events_spec.rb +14 -0
  32. data/spec/fetchers/groups_spec.rb +14 -0
  33. data/spec/fetchers/members_spec.rb +14 -0
  34. data/spec/fetchers/photos_spec.rb +14 -0
  35. data/spec/fetchers/rsvps_spec.rb +14 -0
  36. data/spec/fetchers/topics_spec.rb +14 -0
  37. data/spec/responses/cities.json +1 -0
  38. data/spec/responses/comments.json +1 -0
  39. data/spec/responses/error.json +1 -0
  40. data/spec/responses/events.json +1 -0
  41. data/spec/responses/groups.json +1 -0
  42. data/spec/responses/members.json +1 -0
  43. data/spec/responses/photos.json +1 -0
  44. data/spec/responses/rsvps.json +1 -0
  45. data/spec/responses/topics.json +1 -0
  46. data/spec/spec_helper.rb +82 -0
  47. metadata +138 -0
data/Manifest ADDED
@@ -0,0 +1,45 @@
1
+ Manifest
2
+ README.rdoc
3
+ Rakefile
4
+ lib/rmeetup.rb
5
+ lib/rmeetup/collection.rb
6
+ lib/rmeetup/fetcher.rb
7
+ lib/rmeetup/fetcher/base.rb
8
+ lib/rmeetup/fetcher/cities.rb
9
+ lib/rmeetup/fetcher/comments.rb
10
+ lib/rmeetup/fetcher/events.rb
11
+ lib/rmeetup/fetcher/groups.rb
12
+ lib/rmeetup/fetcher/members.rb
13
+ lib/rmeetup/fetcher/photos.rb
14
+ lib/rmeetup/fetcher/rsvps.rb
15
+ lib/rmeetup/fetcher/topics.rb
16
+ lib/rmeetup/type.rb
17
+ lib/rmeetup/type/city.rb
18
+ lib/rmeetup/type/comment.rb
19
+ lib/rmeetup/type/event.rb
20
+ lib/rmeetup/type/group.rb
21
+ lib/rmeetup/type/member.rb
22
+ lib/rmeetup/type/photo.rb
23
+ lib/rmeetup/type/rsvp.rb
24
+ lib/rmeetup/type/topic.rb
25
+ spec/client_spec.rb
26
+ spec/fetcher_spec.rb
27
+ spec/fetchers/base_spec.rb
28
+ spec/fetchers/cities_spec.rb
29
+ spec/fetchers/comments_spec.rb
30
+ spec/fetchers/events_spec.rb
31
+ spec/fetchers/groups_spec.rb
32
+ spec/fetchers/members_spec.rb
33
+ spec/fetchers/photos_spec.rb
34
+ spec/fetchers/rsvps_spec.rb
35
+ spec/fetchers/topics_spec.rb
36
+ spec/responses/cities.json
37
+ spec/responses/comments.json
38
+ spec/responses/error.json
39
+ spec/responses/events.json
40
+ spec/responses/groups.json
41
+ spec/responses/members.json
42
+ spec/responses/photos.json
43
+ spec/responses/rsvps.json
44
+ spec/responses/topics.json
45
+ spec/spec_helper.rb
data/README.rdoc ADDED
@@ -0,0 +1,34 @@
1
+ = rMeetup
2
+
3
+ A simple Ruby gem to access the Meetup API.
4
+
5
+ == Code Sample
6
+
7
+ Sample code is worth a thousand words:
8
+
9
+ RMeetup::Client.api_key = "API_KEY"
10
+ results = RMeetup::Client.fetch(:events,{:zip => "ZIP_CODE"})
11
+ results.each do |result|
12
+ # Do something with the result
13
+ end
14
+
15
+ RMeetup::Client.fetch takes a data model type and set of options as arguments. Possible data models are:
16
+
17
+ * :topics
18
+ * :cities
19
+ * :members
20
+ * :rsvps
21
+ * :events
22
+ * :groups
23
+ * :comments
24
+ * :photos
25
+
26
+ The options that may be passed can be found on the Meetup API documentation. Please see http://www.meetup.com/meetup_api/docs/ and look up the model that you are calling (i.e. for :events, look at the API call "GET /events" at http://www.meetup.com/meetup_api/docs/events/).
27
+
28
+ == Installation
29
+
30
+
31
+
32
+ == Credit
33
+
34
+ Credit goes to Jared Pace for building the initial iteration of this gem. I just forked it, expanded and documented it a but.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('rMeetup','1.0') do |p|
6
+ p.description = "A simple Ruby gem, providing access to the Meetup API"
7
+ p.url = "https://github.com/Jberlinsky/rmeetup"
8
+ p.author = "Jason Berlinsky"
9
+ p.email = "jason@jasonberlinsky.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*"]
11
+ p.development_dependencies = []
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
@@ -0,0 +1,58 @@
1
+ module RMeetup
2
+ class Collection < Array
3
+ attr_accessor :page_size, :total_results
4
+ attr_writer :current_page
5
+
6
+ def self.build(response)
7
+ collection = Collection.new()
8
+
9
+ # Setup the attributes needed for WillPaginate style paging
10
+ request_url = response['meta']['url']
11
+ request_parameters = parse_parameters_from_url(request_url)
12
+ collection.page_size = request_parameters['page'] ? request_parameters['page'].to_i : nil
13
+ collection.total_results = response['meta']['total_count'].to_i
14
+ collection.current_page = request_parameters['offset'] ? (request_parameters['offset'].to_i + 1) : 1
15
+
16
+ # Load the collection with all
17
+ # of the results we passed in
18
+ response['results'].each do |result|
19
+ collection << result
20
+ end
21
+
22
+ collection
23
+ end
24
+
25
+ # = WillPaginate Helper Methods
26
+ #
27
+ # These methods are implementded so that
28
+ # you may pass this collection to the will_paginate
29
+ # view helper to render pagination links.
30
+ def current_page
31
+ @current_page
32
+ end
33
+
34
+ def total_pages
35
+ @page_size ? (@total_results.to_f / @page_size.to_f).ceil : 1
36
+ end
37
+
38
+ def previous_page
39
+ self.current_page == 1 ? nil : self.current_page.to_i-1
40
+ end
41
+
42
+ def next_page
43
+ self.current_page == self.total_pages ? nil : self.current_page.to_i+1
44
+ end
45
+
46
+ protected
47
+ def self.parse_parameters_from_url(url)
48
+ query = URI.parse(url).query
49
+ parameters = {}
50
+
51
+ query.split("&").each do |kv|
52
+ kv = kv.split("=")
53
+ parameters[kv[0]] = kv[1]
54
+ end
55
+ parameters
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,84 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class ApiError < StandardError
4
+ def initialize(error_message, request_url)
5
+ super "Meetup API Error: #{error_message} - API URL: #{request_url}"
6
+ end
7
+ end
8
+
9
+ class NoResponseError < StandardError
10
+ def initialize
11
+ super "No Response was returned from the Meetup API."
12
+ end
13
+ end
14
+
15
+ # == RMeetup::Fetcher::Base
16
+ #
17
+ # Base fetcher class that other fetchers
18
+ # will inherit from.
19
+ class Base
20
+ def initialize
21
+ @type = nil
22
+ end
23
+
24
+ # Fetch and parse a response
25
+ # based on a set of options.
26
+ # Override this method to ensure
27
+ # neccessary options are passed
28
+ # for the request.
29
+ def fetch(options = {})
30
+ url = build_url(options)
31
+
32
+ json = get_response(url)
33
+ data = JSON.parse(json)
34
+
35
+ # Check to see if the api returned an error
36
+ raise ApiError.new(data['details'],url) if data.has_key?('problem')
37
+
38
+ collection = RMeetup::Collection.build(data)
39
+
40
+ # Format each result in the collection and return it
41
+ collection.map!{|result| format_result(result)}
42
+ end
43
+
44
+ protected
45
+ # OVERRIDE this method to format a result section
46
+ # as per Result type.
47
+ # Takes a result in a collection and
48
+ # formats it to be put back into the collection.
49
+ def format_result(result)
50
+ result
51
+ end
52
+
53
+ def build_url(options)
54
+ options = encode_options(options)
55
+
56
+ base_url + params_for(options)
57
+ end
58
+
59
+ def base_url
60
+ "http://api.meetup.com/#{@type}.json/"
61
+ end
62
+
63
+ # Create a query string from an options hash
64
+ def params_for(options)
65
+ params = []
66
+ options.each do |key, value|
67
+ params << "#{key}=#{value}"
68
+ end
69
+ "?#{params.join("&")}"
70
+ end
71
+
72
+ # Encode a hash of options to be used as request parameters
73
+ def encode_options(options)
74
+ options.each do |key,value|
75
+ options[key] = URI.encode(value.to_s)
76
+ end
77
+ end
78
+
79
+ def get_response(url)
80
+ Net::HTTP.get_response(URI.parse(url)).body || raise(NoResponseError.new)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class Cities < Base
4
+ def initialize
5
+ @type = :cities
6
+ end
7
+
8
+ # Turn the result hash into a City Class
9
+ def format_result(result)
10
+ RMeetup::Type::City.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class Comments < Base
4
+ def initialize
5
+ @type = :comments
6
+ end
7
+
8
+ # Turn the result hash into a Comment Class
9
+ def format_result(result)
10
+ RMeetup::Type::Comment.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class Events < Base
4
+ def initialize
5
+ @type = :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 Groups < Base
4
+ def initialize
5
+ @type = :groups
6
+ end
7
+
8
+ # Turn the result hash into a Group Class
9
+ def format_result(result)
10
+ RMeetup::Type::Group.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class Members < Base
4
+ def initialize
5
+ @type = :members
6
+ end
7
+
8
+ # Turn the result hash into a Member Class
9
+ def format_result(result)
10
+ RMeetup::Type::Member.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class Photos < Base
4
+ def initialize
5
+ @type = :photos
6
+ end
7
+
8
+ # Turn the result hash into a Photo Class
9
+ def format_result(result)
10
+ RMeetup::Type::Photo.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class Rsvps < Base
4
+ def initialize
5
+ @type = :rsvps
6
+ end
7
+
8
+ # Turn the result hash into a Rsvp Class
9
+ def format_result(result)
10
+ RMeetup::Type::Rsvp.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module RMeetup
2
+ module Fetcher
3
+ class Topics < Base
4
+ def initialize
5
+ @type = :topics
6
+ end
7
+
8
+ # Turn the result hash into a Topic Class
9
+ def format_result(result)
10
+ RMeetup::Type::Topic.new(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,38 @@
1
+ require "rmeetup/fetcher/base"
2
+ require "rmeetup/fetcher/topics"
3
+ require "rmeetup/fetcher/cities"
4
+ require "rmeetup/fetcher/members"
5
+ require "rmeetup/fetcher/rsvps"
6
+ require "rmeetup/fetcher/events"
7
+ require "rmeetup/fetcher/groups"
8
+ require "rmeetup/fetcher/comments"
9
+ require "rmeetup/fetcher/photos"
10
+
11
+ module RMeetup
12
+ module Fetcher
13
+
14
+ class << self
15
+ # Return a fetcher for given type
16
+ def for(type)
17
+ return case type.to_sym
18
+ when :topics
19
+ Topics.new
20
+ when :cities
21
+ Cities.new
22
+ when :members
23
+ Members.new
24
+ when :rsvps
25
+ Rsvps.new
26
+ when :events
27
+ Events.new
28
+ when :groups
29
+ Groups.new
30
+ when :comments
31
+ Comments.new
32
+ when :photos
33
+ Photos.new
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
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 City
15
+
16
+ attr_accessor :city
17
+
18
+ def initialize(city = {})
19
+ self.city = city
20
+ end
21
+
22
+ def method_missing(id, *args)
23
+ return self.city[id.id2name]
24
+ end
25
+
26
+ # Special accessors that need typecasting or other parsing
27
+
28
+ def lat
29
+ return self.city['lat'].to_f
30
+ end
31
+ def lon
32
+ return self.city['lon'].to_f
33
+ end
34
+ def members
35
+ return self.city['members'].to_i
36
+ end
37
+ end
38
+ end
39
+ 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 Comment
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
@@ -0,0 +1,47 @@
1
+ module RMeetup
2
+ module Type
3
+
4
+ # == RMeetup::Type::Event
5
+ #
6
+ # Data wraper for a Event fethcing response
7
+ # Used to access result attributes as well
8
+ # as progammatically fetch relative data types
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
+
14
+ class Event
15
+
16
+ attr_accessor :event
17
+
18
+ def initialize(event = {})
19
+ self.event = event
20
+ end
21
+
22
+ def method_missing(id, *args)
23
+ return self.event[id.id2name]
24
+ end
25
+
26
+ # Special accessors that need typecasting or other parsing
27
+ def id
28
+ self.event['id'].to_i
29
+ end
30
+ def lat
31
+ self.event['lat'].to_f
32
+ end
33
+ def lon
34
+ self.event['lon'].to_f
35
+ end
36
+ def rsvpcount
37
+ self.event['rsvpcount'].to_i
38
+ end
39
+ def updated
40
+ DateTime.parse(self.event['updated'])
41
+ end
42
+ def time
43
+ DateTime.parse(self.event['time'])
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,47 @@
1
+ module RMeetup
2
+ module Type
3
+
4
+ # == RMeetup::Type::Group
5
+ #
6
+ # Data wraper for a Group fethcing response
7
+ # Used to access result attributes as well
8
+ # as progammatically fetch relative data types
9
+ # based on this group.
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/groups/ for available fields
13
+
14
+ class Group
15
+ attr_accessor :group
16
+
17
+ def initialize(group = {})
18
+ self.group = group
19
+ end
20
+
21
+ def method_missing(id, *args)
22
+ return self.group[id.id2name]
23
+ end
24
+
25
+ # Special accessors that need typecasting or other parsing
26
+
27
+ def id
28
+ return self.group['id'].to_i
29
+ end
30
+ def updated
31
+ return DateTime.parse(self.group['updated'])
32
+ end
33
+ def created
34
+ return DateTime.parse(self.group['created'])
35
+ end
36
+ def lat
37
+ return self.group['lat'].to_f
38
+ end
39
+ def lon
40
+ return self.group['lon'].to_f
41
+ end
42
+ def daysleft
43
+ return self.group['daysleft'].to_i
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,38 @@
1
+ module RMeetup
2
+ module Type
3
+
4
+ # == RMeetup::Type::Member
5
+ #
6
+ # Data wraper for a Member fethcing response
7
+ # Used to access result attributes as well
8
+ # as progammatically fetch relative data types
9
+ # based on this member.
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/members/ for available fields
13
+
14
+ class Member
15
+ attr_accessor :member
16
+
17
+ def initialize(member = {})
18
+ self.member = member
19
+ end
20
+
21
+ def method_missing(id, *args)
22
+ return self.member[id.id2name]
23
+ end
24
+
25
+ # Special accessors that need typecasting or other parsing
26
+
27
+ def id
28
+ return self.member['id'].to_i
29
+ end
30
+ def lat
31
+ return self.member['lat'].to_f
32
+ end
33
+ def lon
34
+ return self.member['lon'].to_f
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ module RMeetup
2
+ module Type
3
+
4
+ # == RMeetup::Type::Photo
5
+ #
6
+ # Data wraper for a Photo fethcing response
7
+ # Used to access result attributes as well
8
+ # as progammatically fetch relative data types
9
+ # based on this photo.
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/photos/ for available fields
13
+
14
+ class Photo
15
+ attr_accessor :photo
16
+
17
+ def initialize(photo = {})
18
+ self.photo = photo
19
+ end
20
+
21
+ def method_missing(id, *args)
22
+ return self.photo[id.id2name]
23
+ end
24
+
25
+ # Special accessors that need typecasting or other parsing
26
+
27
+ def created
28
+ return DateTime.parse(self.photo['created'])
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ module RMeetup
2
+ module Type
3
+
4
+ # == RMeetup::Type::Rsvp
5
+ #
6
+ # Data wraper for a Rsvp fethcing response
7
+ # Used to access result attributes as well
8
+ # as progammatically fetch relative data types
9
+ # based on this rsvp.
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/rsvps/ for available fields
13
+
14
+ class Rsvp
15
+ attr_accessor :rsvp
16
+
17
+ def initialize(rsvp = {})
18
+ self.rsvp = rsvp
19
+ end
20
+
21
+ def method_missing(id, *args)
22
+ return self.rsvp[id.id2name]
23
+ end
24
+
25
+ # Special accessors that need typecasting or other parsing
26
+
27
+ def lat
28
+ return self.rsvp['lat'].to_f
29
+ end
30
+ def lon
31
+ return self.rsvp['lon'].to_f
32
+ end
33
+ end
34
+ end
35
+ end