reagent-meetup_api 0.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.
data/README ADDED
@@ -0,0 +1,67 @@
1
+ = Meetup API
2
+
3
+ == Developers
4
+ * {Bosco So}[http://boscomonkey.com] <rubymeetup _AT_ boscoso _DOT_ com>
5
+
6
+ == Description
7
+ Meetup API is a port of the official Python client released by Meetup
8
+ for their API. This port provides an object based API to query or
9
+ update Meetup data via pure Ruby. It hides the ugly HTTP/REST calls
10
+ from your code.
11
+
12
+ The Meetup Python API client can be found at
13
+ http://www.meetup.com/meetup_api/clients/
14
+
15
+ == External Dependencies
16
+ * Ruby (tested with 1.8.6)
17
+ * net/http
18
+ * json (tested with versions: 1.1.3)
19
+
20
+ == Usage Examples
21
+ Start by creating an instance of the Meetup object with your API key
22
+ as the constructor argument. You can get your API key at
23
+ http://www.meetup.com/meetup_api/key/
24
+
25
+ mu = MeetupApi::Client.new 'your_api_key'
26
+
27
+ Then, you can query the API directly by using one of the following
28
+ methods:
29
+
30
+ mu.get_events HASH_PARAMS
31
+ mu.get_rsvps HASH_PARAMS
32
+
33
+ Call the method using keyword args containing the parameters of the
34
+ query (identical to parameters described on the main documentation
35
+ page - http://www.meetup.com/meetup_api/docs/). For example, find all
36
+ the events around zip 94108:
37
+
38
+ local_events = mu.get_events :zip => 94108
39
+
40
+ Another example, find the event with id 9348580 (the results method
41
+ still returns an array, but it only has 1 element):
42
+
43
+ ruby_events = mu.get_events :id => 9348580
44
+
45
+ The returned value will be an object of type
46
+ MeetupApi::ApiResponse. This object's property meta is a Hash
47
+ containing all the metadata from the query results. The property
48
+ results is an Array containing objects of type MeetupApi::Event or
49
+ MeetupApi::Rsvp (depending which MeetupApi::Client method was
50
+ used). These objects support additional methods that will make API
51
+ calls to get more information (taking the MeetupApi::Client object as
52
+ an argument to make the request). For example, take the ruby event
53
+ from above and retrieve its RSVP list:
54
+
55
+ first_event = ruby_events.results.first
56
+ rsvps = first_event.get_rsvps mu
57
+
58
+ Of course, if you just wanted to only get the RSVP's, you can simply
59
+ call MeetupApi::Client#get_rsvps directly:
60
+
61
+ rsvps = mu.get_rsvps :event_id => 9348580
62
+
63
+ == To Do
64
+ * Currently, only MeetupApi::Client#get_events and get_rsvps are
65
+ implemented; so, finish the other client methods.
66
+ * Implement OAuth
67
+
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/testtask'
4
+
5
+ task :default => :test
6
+
7
+ spec = Gem::Specification.new do |s|
8
+ s.name = 'meetup_api'
9
+ s.version = '0.1.0'
10
+ s.has_rdoc = true
11
+ s.extra_rdoc_files = %w(README)
12
+ s.rdoc_options = %w(--main README)
13
+ s.summary = "Ruby port of Meetup's official Python API client"
14
+ s.author = 'Bosco So'
15
+ s.email = 'git@boscoso.com'
16
+ s.homepage = 'http://boscoso.com'
17
+ s.files = %w(README Rakefile) + Dir.glob("{lib,test}/**/*")
18
+
19
+ s.add_dependency('json', '= 1.1.3')
20
+ end
21
+
22
+ Rake::GemPackageTask.new(spec) do |pkg|
23
+ pkg.gem_spec = spec
24
+ end
25
+
26
+ Rake::TestTask.new do |t|
27
+ t.libs << 'test'
28
+ t.test_files = FileList["test/**/*_test.rb"]
29
+ t.verbose = true
30
+ end
31
+
32
+ desc 'Generate the gemspec to serve this Gem from Github'
33
+ task :github do
34
+ file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
35
+ File.open(file, 'w') {|f| f << spec.to_ruby }
36
+ puts "Created gemspec: #{file}"
37
+ end
data/lib/meetup_api.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'net/http'
2
+ require 'rubygems'
3
+ require 'json'
4
+
5
+ module MeetupApi
6
+ DEV = ''
7
+ API_BASE_URL = "http://api#{DEV}.meetup.com/"
8
+ EVENTS_URI = 'events'
9
+ RSVPS_URI = 'rsvps'
10
+
11
+ class Client
12
+ def initialize(apiKey)
13
+ @key = apiKey
14
+ end
15
+
16
+ def get_events(args)
17
+ ApiResponse.new(fetch(EVENTS_URI, args), Event)
18
+ end
19
+
20
+ def get_rsvps(args)
21
+ ApiResponse.new(fetch(RSVPS_URI, args), Rsvp)
22
+ end
23
+
24
+ def fetch(uri, url_args={})
25
+ url_args['format'] = 'json'
26
+ url_args['key'] = @key if @key
27
+ args = URI.escape(url_args.collect{|k,v| "#{k}=#{v}"}.join('&'))
28
+ url = "#{API_BASE_URL}#{uri}/?#{args}"
29
+ data = Net::HTTP.get_response(URI.parse(url)).body
30
+
31
+ # ugh - rate limit error throws badly formed JSON
32
+ begin
33
+ JSON.parse(data)
34
+ rescue Exception => e
35
+ raise BaseException(e)
36
+ end
37
+ end
38
+ end
39
+
40
+ class ApiResponse
41
+ attr_reader :meta, :results
42
+
43
+ def initialize(json, klass)
44
+ if (meta_data = json['meta'])
45
+ @meta = meta_data
46
+ @results = json['results'].collect {|hash| klass.new hash}
47
+ else
48
+ raise ClientException.new(json)
49
+ end
50
+ end
51
+ end
52
+
53
+ # Turns a hash into an object - see http://tinyurl.com/97dtjj
54
+ class Hashit
55
+ def initialize(hash)
56
+ hash.each do |k,v|
57
+ # create and initialize an instance variable for this key/value pair
58
+ self.instance_variable_set("@#{k}", v)
59
+ # create the getter that returns the instance variable
60
+ self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})
61
+ # create the setter that sets the instance variable (disabled for readonly)
62
+ ##self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})
63
+ end
64
+ end
65
+ end
66
+
67
+ # Base class for an item in a result set returned by the API.
68
+ class ApiItem < Hashit
69
+ end
70
+
71
+ class Event < ApiItem
72
+ def get_rsvps(apiclient, extraparams={})
73
+ extraparams['event_id'] = self.id
74
+ apiclient.get_rsvps extraparams
75
+ end
76
+
77
+ def to_s
78
+ "Event #{self.id} named #{self.name} at #{self.time} (url: #{self.event_url})"
79
+ end
80
+ end
81
+
82
+ class Rsvp < ApiItem
83
+ def to_s
84
+ "Rsvp by #{self.name} (#{self.link}) with comment: #{self.comment}"
85
+ end
86
+ end
87
+
88
+ # Base class for unexpected errors returned by the Client
89
+ class BaseException < Exception
90
+ attr_reader :problem
91
+
92
+ def initialize(e)
93
+ @problem = e
94
+ end
95
+
96
+ def to_s
97
+ "#{self.problem}"
98
+ end
99
+ end
100
+
101
+ class ClientException < BaseException
102
+ attr_reader :description
103
+
104
+ def initialize(error_json)
105
+ @description = error_json['details']
106
+ @problem = error_json['problem']
107
+ end
108
+
109
+ def to_s
110
+ "#{self.problem}: #{self.description}"
111
+ end
112
+ end
113
+
114
+ end
@@ -0,0 +1,4 @@
1
+ # Copy this file to api_key.rb but make sure you get a real key first
2
+ # from http://www.meetup.com/meetup_api/key/
3
+ #
4
+ API_KEY = "dummy key"
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require File.join(File.expand_path(File.dirname(__FILE__)),
5
+ "..", "lib", "meetup_api")
6
+
7
+ class MeetupApiTester < Test::Unit::TestCase
8
+
9
+ def setup
10
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'api_key')
11
+
12
+ @key = API_KEY
13
+ @api = MeetupApi::Client.new(@key)
14
+ end
15
+
16
+ def test_instantiate_new_client
17
+ end
18
+
19
+ def test_fetch
20
+ # 8337541 is ID for 'My Rake is Bigger than your Rake (Ooga Labs)'
21
+ json = @api.fetch(MeetupApi::RSVPS_URI, :event_id => 8337541)
22
+ assert_not_nil(json, 'json cannot be nil')
23
+ assert_instance_of Hash, json
24
+ assert_equal(2, json.keys.size, 'valid JSON should have only 2 keys')
25
+ json
26
+ end
27
+
28
+ def test_fetch_meta
29
+ json = test_fetch
30
+ meta = json['meta']
31
+ assert_not_nil(meta, "result metadata can't be nil")
32
+ end
33
+
34
+ def test_fetch_results
35
+ json = test_fetch
36
+ results = json['results']
37
+ assert_not_nil(results, "result data can't be nil")
38
+ assert_instance_of Array, results
39
+ assert_equal(62, results.size, "should have 62 RSVP's")
40
+ end
41
+
42
+ def test_fetch_missing_2nd_argument
43
+ json = @api.fetch(MeetupApi::RSVPS_URI)
44
+ assert_not_nil(json)
45
+ end
46
+
47
+ def test_fetch_missing_event_id
48
+ json = @api.fetch(MeetupApi::RSVPS_URI)
49
+ assert_instance_of Hash, json
50
+ assert_equal(2, json.keys.size, 'valid JSON should have only 2 keys')
51
+ assert_not_nil(json['details'])
52
+ assert_not_nil(json['problem'])
53
+ end
54
+
55
+ def test_fetch_unauthorized
56
+ client = MeetupApi::Client.new('invalid_key')
57
+ json = client.fetch(MeetupApi::RSVPS_URI, :event_id => 8337541)
58
+ assert_instance_of Hash, json
59
+ assert_equal(2, json.keys.size, 'valid JSON should have only 2 keys')
60
+ assert_not_nil(json['details'])
61
+ assert_not_nil(json['problem'])
62
+ end
63
+
64
+
65
+ def test_rsvp_valid
66
+ ret = @api.get_rsvps :event_id => 8337541
67
+ verify_my_rake_is_bigger_than_your_rake ret
68
+ end
69
+
70
+ def test_rsvp_missing_id
71
+ begin
72
+ ret = @api.get_rsvps({})
73
+ flunk 'previous call should raise'
74
+ rescue MeetupApi::ClientException => e
75
+ assert_not_nil e.description
76
+ assert_not_nil e.problem
77
+ end
78
+ end
79
+
80
+ def test_events
81
+ ret = @api.get_events :id => 8337541, :after => '01011970'
82
+ assert_not_nil ret.meta
83
+ assert_not_nil ret.results
84
+ assert_instance_of Array, ret.results
85
+ assert_equal 1, ret.results.size
86
+ ret
87
+ end
88
+
89
+ def test_events_rsvps
90
+ events = test_events
91
+ rsvps = events.results.first.get_rsvps @api
92
+ verify_my_rake_is_bigger_than_your_rake rsvps
93
+ end
94
+
95
+ private
96
+
97
+ def verify_my_rake_is_bigger_than_your_rake(ret)
98
+ assert_not_nil ret, "RSVP's for 'My Rake...' event should not be nil"
99
+ assert_not_nil ret.meta
100
+ assert_not_nil ret.results
101
+ assert_instance_of Array, ret.results
102
+ assert_equal 62, ret.results.size
103
+ ret.results.each {|r| assert_instance_of MeetupApi::Rsvp, r}
104
+ end
105
+
106
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reagent-meetup_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Bosco So
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-04 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - "="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.1.3
23
+ version:
24
+ description:
25
+ email: user@example.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README
32
+ files:
33
+ - README
34
+ - Rakefile
35
+ - lib/meetup_api.rb
36
+ - test/api_key.README
37
+ - test/meetup_api_tester.rb
38
+ has_rdoc: true
39
+ homepage: http://example.com
40
+ post_install_message:
41
+ rdoc_options:
42
+ - --main
43
+ - README
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.2.0
62
+ signing_key:
63
+ specification_version: 2
64
+ summary: Ruby port of Meetup's official Python API client
65
+ test_files: []
66
+