rMeetup 1.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.
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