thecity 0.0.2
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.
- 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
|