rubeetup 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ module Rubeetup
2
+ ##
3
+ # @author Mike Vascelli <michele.vascelli@gmail.com>
4
+ #
5
+ # Requester instances perform requests for the user
6
+ #
7
+ class Requester
8
+ include Rubeetup::Utilities
9
+
10
+ ##
11
+ # @return [Hash{Symbol=>String}] this Requester's auth data
12
+ #
13
+ attr_reader :auth
14
+
15
+ ##
16
+ # @return [Symbol] the chosen request builder
17
+ #
18
+ attr_reader :request_builder
19
+
20
+ ##
21
+ # @param [Hash{Symbol=>String}] args holds auth data to send with each request
22
+ # @option args [String] :key the api key
23
+ #
24
+ def initialize(args)
25
+ self.auth = args
26
+ @request_builder = Rubeetup::RequestBuilder
27
+ end
28
+
29
+ ##
30
+ # Sets auth data, and validates it.
31
+ # @param [Hash{Symbol=>String}] args holds auth data to send with each request
32
+ # @option args [String] :key the api key
33
+ # @raise [Rubeetup::InvalidAuthenticationError] if the passed auth data is not a Hash,
34
+ # or if it does not include key: 'val'
35
+ #
36
+ def auth=(args)
37
+ @auth = args
38
+ validate_auth
39
+ end
40
+
41
+
42
+ ##
43
+ # Performs the actual request, by dynamically creating a Request instance,
44
+ # and by then executing it.
45
+ # @param [Symbol] name request name
46
+ # @param [Array<Hash{Symbol=>String}, ...>] args holds the request options
47
+ # @return [Array<Rubeetup::ResponseWrapper>] the request response
48
+ #
49
+ def method_missing(name, *args)
50
+ merge_auth(args)
51
+ request = request_builder.compose_request(name, args)
52
+ request.execute
53
+ end
54
+
55
+ private
56
+
57
+ def validate_auth
58
+ fail Rubeetup::InvalidAuthenticationError, 'Must respond to #merge' unless
59
+ auth.respond_to? :merge
60
+ fail Rubeetup::InvalidAuthenticationError, "Requires ---> {key: /[^\s]+/}" unless
61
+ (val = auth[:key]) && present?(val)
62
+ end
63
+
64
+ # Operates on the memory referenced by args
65
+ # @note should both auth, and args have the same keys, then the keys in auth
66
+ # will overwrite those in options. This guarantees that if the user
67
+ # includes api keys while sending a request, those will be ignored.
68
+ #
69
+ def merge_auth(args)
70
+ options = args[0]
71
+ args[0] = options.respond_to?(:merge) ? options.merge(auth) : auth
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,79 @@
1
+ require 'rubeetup/requests_lib/meetup_catalog'
2
+
3
+ module Rubeetup
4
+ ##
5
+ # Provides an interface to an abstract catalog of all the supported requests.
6
+ # The concrete catalogs are provided in the +rubeetup/requests_lib+ folder,
7
+ # and they are fetched by #build_catalog
8
+ # @note This module expects to be mixed in to a class which implements
9
+ # the instance method +#name+.
10
+ #
11
+ module RequestsCatalog
12
+ ##
13
+ # @return [Boolean] whether a +name+ entry exists in the catalog
14
+ #
15
+ def is_in_catalog?
16
+ catalog[name]
17
+ end
18
+
19
+ ##
20
+ # Reads the +name+ entry in the catalog and then gets its required parameters
21
+ # @note this module expects a concrete catalog whose entries can respond to +[:options]+
22
+ # @return [Array<Symbol>] the list of all the required parameters
23
+ #
24
+ def required_options
25
+ catalog[name][:options]
26
+ end
27
+
28
+ ##
29
+ # Reads the +name+ entry in the catalog and then gets its lambda to compute the request's path
30
+ # @note this module expects a concrete catalog whose entries can respond to +[:path]+
31
+ # @return [Lambda] the lambda expression to compute the path for the request
32
+ #
33
+ def request_path
34
+ path = catalog[name][:path]
35
+ eval path if path
36
+ end
37
+
38
+ ##
39
+ # Reads the +name+ entry in the catalog and then gets its POST logic if defined
40
+ # @note the entry in the concrete catalog may not respond to +:[:multipart]+
41
+ # @return [Lambda] If defined, it provides the logic to encode for multipart POST
42
+ #
43
+ def request_multipart
44
+ multi = catalog[name][:multipart]
45
+ eval multi if multi
46
+ end
47
+
48
+ private
49
+
50
+ ##
51
+ # @todo Could be fitted to take an arg, or even an attribute, to decide which
52
+ # catalog should be built dynamically...
53
+ #
54
+ def catalog
55
+ Rubeetup::RequestsCatalog.send(:build_catalog)
56
+ end
57
+
58
+ ##
59
+ # Gives you the list of all the supported requests
60
+ # @return [Array<Symbol>] the complete list of supported operations
61
+ #
62
+ def self.supported_requests
63
+ build_catalog.keys
64
+ end
65
+
66
+ ##
67
+ # Here we choose the catalog we want to build.
68
+ # Then we load the catalog into a class instance variable. This should speed up
69
+ # processing, but may be costly in terms of space.
70
+ # @todo analyze the situation and decide whether to load the catalog at each
71
+ # request
72
+ #
73
+ def self.build_catalog
74
+ @data ||= Rubeetup::MeetupCatalog.requests
75
+ end
76
+
77
+ private_class_method :build_catalog
78
+ end
79
+ end