thecity 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.md +45 -0
- data/README.md +170 -0
- data/Rakefile +11 -0
- data/lib/the_city/account.rb +32 -0
- data/lib/the_city/api/accounts.rb +34 -0
- data/lib/the_city/api/client.rb +136 -0
- data/lib/the_city/api/events.rb +55 -0
- data/lib/the_city/api/groups.rb +41 -0
- data/lib/the_city/api/needs.rb +51 -0
- data/lib/the_city/api/oauth.rb +50 -0
- data/lib/the_city/api/prayers.rb +51 -0
- data/lib/the_city/api/request/multipart_with_file.rb +36 -0
- data/lib/the_city/api/response/parse_json.rb +27 -0
- data/lib/the_city/api/response/raise_error.rb +28 -0
- data/lib/the_city/api/topics.rb +51 -0
- data/lib/the_city/api/users.rb +78 -0
- data/lib/the_city/api/utils.rb +58 -0
- data/lib/the_city/arguments.rb +11 -0
- data/lib/the_city/base.rb +133 -0
- data/lib/the_city/client.rb +94 -0
- data/lib/the_city/collection.rb +130 -0
- data/lib/the_city/content.rb +29 -0
- data/lib/the_city/error/argument_arror.rb +8 -0
- data/lib/the_city/error/bad_gateway.rb +10 -0
- data/lib/the_city/error/bad_request.rb +10 -0
- data/lib/the_city/error/configuration_error.rb +8 -0
- data/lib/the_city/error/forbidden.rb +10 -0
- data/lib/the_city/error/gateway_timeout.rb +10 -0
- data/lib/the_city/error/internal_server_error.rb +10 -0
- data/lib/the_city/error/not_acceptable.rb +10 -0
- data/lib/the_city/error/not_found.rb +10 -0
- data/lib/the_city/error/service_unavailable.rb +10 -0
- data/lib/the_city/error/too_many_requests.rb +12 -0
- data/lib/the_city/error/unauthorized.rb +10 -0
- data/lib/the_city/error/unprocessable_entity.rb +10 -0
- data/lib/the_city/error.rb +66 -0
- data/lib/the_city/event.rb +11 -0
- data/lib/the_city/group.rb +6 -0
- data/lib/the_city/need.rb +10 -0
- data/lib/the_city/permissions.rb +21 -0
- data/lib/the_city/prayer.rb +10 -0
- data/lib/the_city/rate_limit.rb +17 -0
- data/lib/the_city/terminology.rb +39 -0
- data/lib/the_city/time.rb +67 -0
- data/lib/the_city/token.rb +16 -0
- data/lib/the_city/topic.rb +10 -0
- data/lib/the_city/user.rb +41 -0
- data/lib/the_city/version.rb +18 -0
- data/lib/the_city.rb +15 -0
- data/thecity.gemspec +28 -0
- 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,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
|