thecity 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/LICENSE.md +45 -0
  4. data/README.md +170 -0
  5. data/Rakefile +11 -0
  6. data/lib/the_city/account.rb +32 -0
  7. data/lib/the_city/api/accounts.rb +34 -0
  8. data/lib/the_city/api/client.rb +136 -0
  9. data/lib/the_city/api/events.rb +55 -0
  10. data/lib/the_city/api/groups.rb +41 -0
  11. data/lib/the_city/api/needs.rb +51 -0
  12. data/lib/the_city/api/oauth.rb +50 -0
  13. data/lib/the_city/api/prayers.rb +51 -0
  14. data/lib/the_city/api/request/multipart_with_file.rb +36 -0
  15. data/lib/the_city/api/response/parse_json.rb +27 -0
  16. data/lib/the_city/api/response/raise_error.rb +28 -0
  17. data/lib/the_city/api/topics.rb +51 -0
  18. data/lib/the_city/api/users.rb +78 -0
  19. data/lib/the_city/api/utils.rb +58 -0
  20. data/lib/the_city/arguments.rb +11 -0
  21. data/lib/the_city/base.rb +133 -0
  22. data/lib/the_city/client.rb +94 -0
  23. data/lib/the_city/collection.rb +130 -0
  24. data/lib/the_city/content.rb +29 -0
  25. data/lib/the_city/error/argument_arror.rb +8 -0
  26. data/lib/the_city/error/bad_gateway.rb +10 -0
  27. data/lib/the_city/error/bad_request.rb +10 -0
  28. data/lib/the_city/error/configuration_error.rb +8 -0
  29. data/lib/the_city/error/forbidden.rb +10 -0
  30. data/lib/the_city/error/gateway_timeout.rb +10 -0
  31. data/lib/the_city/error/internal_server_error.rb +10 -0
  32. data/lib/the_city/error/not_acceptable.rb +10 -0
  33. data/lib/the_city/error/not_found.rb +10 -0
  34. data/lib/the_city/error/service_unavailable.rb +10 -0
  35. data/lib/the_city/error/too_many_requests.rb +12 -0
  36. data/lib/the_city/error/unauthorized.rb +10 -0
  37. data/lib/the_city/error/unprocessable_entity.rb +10 -0
  38. data/lib/the_city/error.rb +66 -0
  39. data/lib/the_city/event.rb +11 -0
  40. data/lib/the_city/group.rb +6 -0
  41. data/lib/the_city/need.rb +10 -0
  42. data/lib/the_city/permissions.rb +21 -0
  43. data/lib/the_city/prayer.rb +10 -0
  44. data/lib/the_city/rate_limit.rb +17 -0
  45. data/lib/the_city/terminology.rb +39 -0
  46. data/lib/the_city/time.rb +67 -0
  47. data/lib/the_city/token.rb +16 -0
  48. data/lib/the_city/topic.rb +10 -0
  49. data/lib/the_city/user.rb +41 -0
  50. data/lib/the_city/version.rb +18 -0
  51. data/lib/the_city.rb +15 -0
  52. data/thecity.gemspec +28 -0
  53. metadata +172 -0
@@ -0,0 +1,51 @@
1
+ require 'the_city/arguments'
2
+ require 'the_city/api/utils'
3
+ require 'the_city/prayer'
4
+
5
+ module TheCity
6
+ module API
7
+ module prayers
8
+ include TheCity::API::Utils
9
+
10
+ # Posts a prayer to The City
11
+ #
12
+ # @see https://api.onthecity.org/docs
13
+ #
14
+ # @req_scope group_content
15
+ # @return [TheCity::Prayer]
16
+ # @param options [Hash] A customizable set of options.
17
+ # @option options [Integer] :group_id The id of the group you will be posting to.
18
+ # @option options [String] :title The title of the prayer.
19
+ # @option options [String] :body The body text of the prayer.
20
+ def post_prayer(options)
21
+ raise(Error::ArgumentError, "Must supply a options[:group_id] for the prayers's originating group") unless options[:group_id]
22
+ raise(Error::ArgumentError, "Title (options[:title]) required") unless options[:title]
23
+ raise(Error::ArgumentError, "Body (options[:body]) required") unless options[:body]
24
+ gid = options[:group_id] || 0
25
+ object_from_response(TheCity::Prayer, :post, "/groups/#{gid}/prayers/", options, {:client => self})
26
+ end
27
+
28
+ # Returns a prayer by id
29
+ #
30
+ # @see https://api.onthecity.org/docs
31
+ #
32
+ # @req_scope group_content
33
+ # @return [TheCity::Prayer]
34
+ # @raise [TheCity::Error::NotFound] Error raised when the prayer cannot be found.
35
+ # @overload prayer(id)
36
+ # @param id [Integer] The id of the prayer.
37
+ # @overload prayer(id, options={})
38
+ # @param id [Integer] The id of the prayer.
39
+ # @param options [Hash] A customizable set of options.
40
+ # @option options [Boolean] :force_download Forces the request to hit the server and flush the cached response
41
+ def prayer(*args)
42
+ @prayers ||= {}
43
+ arguments = TheCity::Arguments.new(args)
44
+ pid = args.shift
45
+ @prayers[pid] = nil if arguments.options.delete(:force_download)
46
+ @prayers[pid] ||= object_from_response(TheCity::Prayer, :get, "/prayers/#{pid}", arguments.options, {:client => self})
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ require 'faraday'
2
+
3
+ module TheCity
4
+ module API
5
+ module Request
6
+ class MultipartWithFile < Faraday::Middleware
7
+ CONTENT_TYPE = 'Content-Type'
8
+
9
+ def call(env)
10
+ for key, value in env[:body]
11
+ if value.respond_to?(:to_io)
12
+ env[:body][key] = Faraday::UploadIO.new(value, mime_type(value.path), value.path)
13
+ end
14
+ end if env[:body].is_a?(::Hash)
15
+ @app.call(env)
16
+ end
17
+
18
+ private
19
+
20
+ def mime_type(path)
21
+ case path
22
+ when /\.jpe?g/i
23
+ 'image/jpeg'
24
+ when /\.gif$/i
25
+ 'image/gif'
26
+ when /\.png$/i
27
+ 'image/png'
28
+ else
29
+ 'application/octet-stream'
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,27 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module TheCity
5
+ module API
6
+ module Response
7
+ class ParseJson < Faraday::Response::Middleware
8
+
9
+ def parse(body)
10
+ case body
11
+ when /\A^\s*$\z/, nil
12
+ nil
13
+ else
14
+ JSON.parse(body, :symbolize_names => true)
15
+ end
16
+ end
17
+
18
+ def on_complete(env)
19
+ if respond_to?(:parse)
20
+ env[:body] = parse(env[:body]) unless [204, 301, 302, 304].include?(env[:status])
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ require 'faraday'
2
+ require 'the_city/error/bad_gateway'
3
+ require 'the_city/error/bad_request'
4
+ require 'the_city/error/forbidden'
5
+ require 'the_city/error/gateway_timeout'
6
+ require 'the_city/error/internal_server_error'
7
+ require 'the_city/error/not_acceptable'
8
+ require 'the_city/error/not_found'
9
+ require 'the_city/error/service_unavailable'
10
+ require 'the_city/error/too_many_requests'
11
+ require 'the_city/error/unauthorized'
12
+ require 'the_city/error/unprocessable_entity'
13
+
14
+ module TheCity
15
+ module API
16
+ module Response
17
+ class RaiseError < Faraday::Response::Middleware
18
+
19
+ def on_complete(env)
20
+ status_code = env[:status].to_i
21
+ error_class = TheCity::Error.errors[status_code]
22
+ raise error_class.from_response(env) if error_class
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,51 @@
1
+ require 'the_city/arguments'
2
+ require 'the_city/api/utils'
3
+ require 'the_city/topic'
4
+
5
+ module TheCity
6
+ module API
7
+ module Topics
8
+ include TheCity::API::Utils
9
+
10
+ # Posts a topic to The City
11
+ #
12
+ # @see https://api.onthecity.org/docs
13
+ #
14
+ # @req_scope group_content
15
+ # @return [TheCity::Topic]
16
+ # @param options [Hash] A customizable set of options.
17
+ # @option options [Integer] :group_id The id of the group you will be posting to.
18
+ # @option options [String] :title The title of the topic.
19
+ # @option options [String] :body The body text of the topic.
20
+ def post_topic(options)
21
+ raise(Error::ArgumentError, "Must supply a options[:group_id] for the topic's originating group") unless options[:group_id]
22
+ raise(Error::ArgumentError, "Title (options[:title]) required") unless options[:title]
23
+ raise(Error::ArgumentError, "Body (options[:body]) required") unless options[:body]
24
+ gid = options[:group_id] || 0
25
+ object_from_response(TheCity::Topic, :post, "/groups/#{gid}/topics/", options, {:client => self})
26
+ end
27
+
28
+ # Returns a topic by id
29
+ #
30
+ # @see https://api.onthecity.org/docs
31
+ #
32
+ # @req_scope group_content
33
+ # @return [TheCity::Topic]
34
+ # @raise [TheCity::Error::NotFound] Error raised when the topic cannot be found.
35
+ # @overload topic(id)
36
+ # @param id [Integer] The id of the topic.
37
+ # @overload topic(id, options={})
38
+ # @param id [Integer] The id of the topic.
39
+ # @param options [Hash] A customizable set of options.
40
+ # @option options [Boolean] :force_download Forces the request to hit the server and flush the cached response
41
+ def topic(*args)
42
+ @topics ||= {}
43
+ arguments = TheCity::Arguments.new(args)
44
+ tid = args.shift
45
+ @topics[tid] = nil if arguments.options.delete(:force_download)
46
+ @topics[tid] ||= object_from_response(TheCity::Topic, :get, "/topics/#{tid}", arguments.options, {:client => self})
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,78 @@
1
+ require 'the_city/api/utils'
2
+
3
+ module TheCity
4
+ module API
5
+ module Users
6
+ include TheCity::API::Utils
7
+
8
+ # @see https://api.onthecity.org/docs
9
+ #
10
+ # @return [TheCity::User] The requested user.
11
+ # @raise [TheCity::Error::NotFound] Error raised when the user cannot be found.
12
+ # @req_scope user_trusted
13
+ # @overload user(id)
14
+ # @param id [Integer] The id of the user.
15
+ # @overload user(id, options={})
16
+ # @param id [Integer] The id of the user.
17
+ # @param options [Hash] A customizable set of options.
18
+ # @option options [Boolean] :force_download Forces the request to hit the server and flush the cached response
19
+ def user(*args)
20
+ @users ||= {}
21
+ arguments = TheCity::Arguments.new(args)
22
+ uid = args.shift
23
+ @users[uid] = nil if arguments.options.delete(:force_download)
24
+ @users[uid] ||= object_from_response(TheCity::User, :get, "/users/#{uid}", arguments.options, {:client => self})
25
+ end
26
+
27
+ # Returns the user associated with the current access token
28
+ #
29
+ # @see https://api.onthecity.org/docs
30
+ #
31
+ # @req_scope user_basic
32
+ # @opt_scope user_extended
33
+ # @return [TheCity::User] The authenticated user.
34
+ # @param options [Hash] A customizable set of options.
35
+ # @option options [Boolean] :force_download Forces the request to hit the server and flush the cached response
36
+ def me(options={})
37
+ @me = nil if options.delete(:force_download)
38
+ @me ||= object_from_response(TheCity::User, :get, "/me", options, {:current_user => true, :client => self})
39
+ end
40
+ alias current_user me
41
+
42
+ # Returns the permissions for the current user
43
+ #
44
+ # @see https://api.onthecity.org/docs
45
+ #
46
+ # @req_scope user_permissions
47
+ # @opt_scope group_content
48
+ # @return [TheCity::Permissions] The permission object for the current user.
49
+ # @overload permissions(options={})
50
+ # @param options [Hash] A customizable set of options.
51
+ def permissions(*args)
52
+ arguments = TheCity::Arguments.new(args)
53
+ object_from_response(TheCity::Permissions, :get, "/me/permissions", arguments.options)
54
+ end
55
+
56
+ # Returns true if the specified user exists
57
+ #
58
+ # @req_scope user_trusted
59
+ # @return [Boolean] true if the user exists, otherwise false.
60
+ # @param user [Integer, String, TheCity::User] A City user id, or object.
61
+ def user?(user)
62
+ user_id = case user
63
+ when ::Integer
64
+ user
65
+ when ::String
66
+ user.to_i
67
+ when TheCity::User
68
+ user.id
69
+ end
70
+ get("/users/#{user_id}")
71
+ true
72
+ rescue TheCity::Error::NotFound
73
+ false
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,58 @@
1
+ require 'the_city/arguments'
2
+ require 'the_city/collection'
3
+ require 'the_city/user'
4
+ require 'the_city/group'
5
+ require 'the_city/account'
6
+ require 'uri'
7
+
8
+ module TheCity
9
+ module API
10
+ module Utils
11
+
12
+ private
13
+
14
+ # @param klass [Class]
15
+ # @param request_method [Symbol]
16
+ # @param path [String]
17
+ # @param request_options [Hash]
18
+ # @param options [Hash]
19
+ # @return [Array]
20
+ def objects_from_response(klass, request_method, path, request_options={}, options ={})
21
+ response = send(request_method.to_sym, path, request_options)[:body]
22
+ objects_from_array(klass, response, options)
23
+ end
24
+
25
+ # @param klass [Class]
26
+ # @param array [Array]
27
+ # @return [Array]
28
+ def objects_from_array(klass, array, options={})
29
+ array.map do |element|
30
+ klass.new(element, options)
31
+ end
32
+ end
33
+
34
+ # @param klass [Class]
35
+ # @param request_method [Symbol]
36
+ # @param path [String]
37
+ # @param request_options [Hash]
38
+ # @param options [Hash]
39
+ # @return [Object]
40
+ def object_from_response(klass, request_method, path, request_options={}, options ={})
41
+ response = send(request_method.to_sym, path, request_options)
42
+ klass.from_response(response, options)
43
+ end
44
+
45
+ # @param collection_name [Symbol]
46
+ # @param klass [Class]
47
+ # @param request_method [Symbol]
48
+ # @param path [String]
49
+ # @param request_options [Hash]
50
+ # @return [TheCity::Collection]
51
+ def collection_from_response(collection_name, klass, request_method, path, request_options)
52
+ response = send(request_method.to_sym, path, request_options)
53
+ TheCity::Collection.from_response(response, collection_name.to_sym, klass, self, request_method, path, request_options)
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ module TheCity
2
+ class Arguments < Array
3
+ attr_reader :options
4
+
5
+ def initialize(args)
6
+ @options = args.last.is_a?(::Hash) ? args.pop : {}
7
+ super(args)
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,133 @@
1
+ require 'forwardable'
2
+ require 'uri'
3
+
4
+ module TheCity
5
+ class Base
6
+ extend Forwardable
7
+ attr_reader :attrs
8
+ alias to_h attrs
9
+ alias to_hash attrs
10
+ alias to_hsh attrs
11
+ def_delegators :attrs, :delete, :update
12
+
13
+ # Define methods that retrieve the value from attributes
14
+ #
15
+ # @param attrs [Array, Symbol]
16
+ def self.attr_reader(*attrs)
17
+ for attr in attrs
18
+ define_attribute_method(attr)
19
+ define_predicate_method(attr)
20
+ end
21
+ end
22
+
23
+ # Define object methods from attributes
24
+ #
25
+ # @param klass [Symbol]
26
+ # @param key1 [Symbol]
27
+ # @param key2 [Symbol]
28
+ def self.object_attr_reader(klass, key1, key2=nil)
29
+ define_attribute_method(key1, klass, key2)
30
+ define_predicate_method(key1)
31
+ end
32
+
33
+ # Define URI methods from attributes
34
+ #
35
+ # @param attrs [Array, Symbol]
36
+ def self.uri_attr_reader(*attrs)
37
+ for uri_key in attrs
38
+ array = uri_key.to_s.split("_")
39
+ index = array.index("uri")
40
+ array[index] = "url"
41
+ url_key = array.join("_").to_sym
42
+ define_uri_method(uri_key, url_key)
43
+ define_predicate_method(uri_key, url_key)
44
+ alias_method(url_key, uri_key)
45
+ alias_method("#{url_key}?", "#{uri_key}?")
46
+ end
47
+ end
48
+
49
+ # Dynamically define a method for a URI
50
+ #
51
+ # @param key1 [Symbol]
52
+ # @param key2 [Symbol]
53
+ def self.define_uri_method(key1, key2)
54
+ define_method(key1) do
55
+ memoize(key1) do
56
+ ::URI.parse(@attrs[key2]) if @attrs[key2]
57
+ end
58
+ end
59
+ end
60
+
61
+ # Dynamically define a method for an attribute
62
+ #
63
+ # @param key1 [Symbol]
64
+ # @param klass [Symbol]
65
+ # @param key2 [Symbol]
66
+ def self.define_attribute_method(key1, klass=nil, key2=nil)
67
+ define_method(key1) do
68
+
69
+ memoize(key1) do
70
+ if klass.nil?
71
+ @attrs[key1]
72
+ else
73
+ if @attrs[key1]
74
+ if key2.nil?
75
+ TheCity.const_get(klass).new(@attrs[key1])
76
+ else
77
+ attrs = @attrs.dup
78
+ value = attrs.delete(key1)
79
+ TheCity.const_get(klass).new(value.update(key2 => attrs))
80
+ end
81
+ else
82
+ TheCity::NullObject.instance
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ # Dynamically define a predicate method for an attribute
90
+ #
91
+ # @param key1 [Symbol]
92
+ # @option key2 [Symbol]
93
+ def self.define_predicate_method(key1, key2=key1)
94
+ define_method(:"#{key1}?") do
95
+ !!@attrs[key2]
96
+ end
97
+ end
98
+
99
+ # Construct an object from a response hash
100
+ #
101
+ # @param response [Hash]
102
+ # @return [TheCity::Base]
103
+ def self.from_response(response, options)
104
+ new(response[:body], options)
105
+ end
106
+
107
+ # Initializes a new object
108
+ #
109
+ # @param attrs [Hash]
110
+ # @return [TheCity::Base]
111
+ def initialize(attrs={}, options={})
112
+ @attrs = attrs || {}
113
+ @client = options.delete(:client) rescue nil
114
+ end
115
+
116
+ # Fetches an attribute of an object using hash notation
117
+ #
118
+ # @param method [String, Symbol] Message to send to the object
119
+ def [](method)
120
+ send(method.to_sym)
121
+ rescue NoMethodError
122
+ nil
123
+ end
124
+
125
+ def memoize(key, &block)
126
+ ivar = :"@#{key}"
127
+ return instance_variable_get(ivar) if instance_variable_defined?(ivar)
128
+ result = block.call
129
+ instance_variable_set(ivar, result)
130
+ end
131
+
132
+ end
133
+ end
@@ -0,0 +1,94 @@
1
+ require 'the_city/version'
2
+ require 'uri'
3
+
4
+ module TheCity
5
+ class Client
6
+ attr_writer :access_token, :app_id, :app_secret, :subdomain, :version
7
+ alias oauth_token= access_token=
8
+
9
+ # Initializes a new Client object
10
+ #
11
+ # @param options [Hash]
12
+ # @return [TheCity::API::Client]
13
+ def initialize(options={})
14
+ for key, value in options
15
+ send(:"#{key}=", value)
16
+ end
17
+ yield self if block_given?
18
+ end
19
+
20
+ # @return [String]
21
+ def subdomain
22
+ if instance_variable_defined?(:@subdomain)
23
+ @subdomain
24
+ else
25
+ ENV['THECITY_SUBDOMAIN']
26
+ end
27
+ end
28
+
29
+ # @return [String]
30
+ def app_id
31
+ if instance_variable_defined?(:@app_id)
32
+ @app_id
33
+ else
34
+ ENV['THECITY_APP_ID']
35
+ end
36
+ end
37
+
38
+ # @return [String]
39
+ def app_secret
40
+ if instance_variable_defined?(:@app_secret)
41
+ @app_secret
42
+ else
43
+ ENV['THECITY_APP_SECRET']
44
+ end
45
+ end
46
+
47
+ # @return [String]
48
+ def access_token
49
+ if instance_variable_defined?(:@access_token)
50
+ @access_token
51
+ else
52
+ ENV['THECITY_ACCESS_TOKEN']
53
+ end
54
+ end
55
+ alias oauth_token access_token
56
+
57
+ # @return [String]
58
+ def version
59
+ if instance_variable_defined?(:@version)
60
+ @api_version || "1"
61
+ elsif ENV['THECITY_API_VERSION']
62
+ ENV['THECITY_API_VERSION']
63
+ else
64
+ "1"
65
+ end
66
+ end
67
+ alias api_version version
68
+
69
+ # @return [Hash]
70
+ def credentials
71
+ {
72
+ :app_id => app_id,
73
+ :app_secret => app_secret,
74
+ :token => access_token,
75
+ }
76
+ end
77
+
78
+ # @return [Boolean]
79
+ def credentials?
80
+ credentials.values.all?
81
+ end
82
+
83
+ private
84
+
85
+ # Ensures that all credentials set during configuration are of a
86
+ # valid type. Valid types are String and Symbol.
87
+ def validate_credentials!
88
+ for credential, value in credentials
89
+ raise(Error::ConfigurationError, "Invalid #{credential} specified: #{value.inspect} must be a string or symbol.") unless value.is_a?(String) || value.is_a?(Symbol)
90
+ end
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,130 @@
1
+ module TheCity
2
+ # Utility class for collections with paged responses
3
+ class Collection
4
+ include Enumerable
5
+ attr_reader :attrs
6
+ alias to_h attrs
7
+ alias to_hash attrs
8
+ alias to_hsh attrs
9
+
10
+ # Construct a new Collection object from a response hash
11
+ #
12
+ # @param response [Hash]
13
+ # @param key [String, Symbol] The key to fetch the data from the response
14
+ # @param klass [Class] The class to instantiate objects in the response
15
+ # @param client [TheCity::API::Client]
16
+ # @param request_method [String, Symbol]
17
+ # @param path [String]
18
+ # @param options [Hash]
19
+ # @return [TheCity::Collection]
20
+ def self.from_response(response, key, klass, client, request_method, path, options)
21
+ new(response[:body], key, klass, client, request_method, path, options)
22
+ end
23
+
24
+ # Initializes a new Collection
25
+ #
26
+ # @param attrs [Hash]
27
+ # @param key [String, Symbol] The key to fetch the data from the response
28
+ # @param klass [Class] The class to instantiate objects in the response
29
+ # @param client [TheCity::API::Client]
30
+ # @param request_method [String, Symbol]
31
+ # @param path [String]
32
+ # @param options [Hash]
33
+ # @return [TheCity::Collection]
34
+ def initialize(attrs, key, klass, client, request_method, path, options)
35
+ @key = key.to_sym
36
+ @klass = klass
37
+ @client = client
38
+ @request_method = request_method.to_sym
39
+ @path = path
40
+ @options = options
41
+ @collection = []
42
+ set_attrs(attrs)
43
+ end
44
+
45
+ # @return [Enumerator]
46
+ def each(start = 0, &block)
47
+ return to_enum(:each) unless block_given?
48
+ for element in Array(@collection[start..-1])
49
+ yield element
50
+ @current_cursor += 1
51
+ end
52
+ unless last?
53
+ start = [@collection.size, start].max
54
+ fetch_next_page unless last_page?
55
+ each(start, &block)
56
+ end
57
+ @current_cursor = 1
58
+ self
59
+ end
60
+
61
+ def current_cursor
62
+ @current_cursor
63
+ end
64
+
65
+ def next_cursur
66
+ (current_cursor + 1) || -1
67
+ end
68
+ alias next next_cursur
69
+
70
+ def previous_cursor
71
+ current_cursor - 1
72
+ end
73
+ alias previous previous_cursor
74
+
75
+ # @return [Boolean]
76
+ def first?
77
+ previous_cursor.zero?
78
+ end
79
+
80
+ # @return [Boolean]
81
+ def last?
82
+ current_cursor >= total_entries
83
+ end
84
+
85
+ def current_page
86
+ @current_page
87
+ end
88
+
89
+ def next_page
90
+ current_page + 1
91
+ end
92
+
93
+ def last_page?
94
+ current_page == @total_pages
95
+ end
96
+
97
+ def total_entries
98
+ @total_entries.is_a?(Array) ? @total_entries.first : @total_entries
99
+ end
100
+ alias total total_entries
101
+
102
+ def [](n)
103
+ @collection[n]
104
+ end
105
+
106
+ def last
107
+ @collection.last
108
+ end
109
+
110
+ private
111
+
112
+ def fetch_next_page
113
+ response = @client.send(@request_method, @path, @options.merge(:page => next_page, :per_page => @per_page))
114
+ set_attrs(response[:body])
115
+ end
116
+
117
+ def set_attrs(attrs)
118
+ @attrs = attrs
119
+ for element in Array(attrs[@key])
120
+ @collection << (@klass ? @klass.new(element) : element)
121
+ end
122
+ @total_entries = attrs[:total_entries],
123
+ @current_page = attrs[:current_page],
124
+ @total_pages = attrs[:total_pages],
125
+ @per_page = attrs[:per_page],
126
+ @current_cursor = ((@current_page - 1) * @per_page) + 1
127
+ end
128
+
129
+ end
130
+ end