vkontakte_api 0.2.1 → 1.0.rc
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/.rspec +1 -0
- data/.travis.yml +1 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +23 -0
- data/README.md +136 -61
- data/lib/generators/vkontakte_api/install/USAGE +2 -0
- data/lib/generators/vkontakte_api/install/install_generator.rb +9 -0
- data/lib/generators/vkontakte_api/install/templates/initializer.rb +22 -0
- data/lib/vkontakte_api/api.rb +27 -39
- data/lib/vkontakte_api/authorization.rb +66 -0
- data/lib/vkontakte_api/client.rb +14 -12
- data/lib/vkontakte_api/configuration.rb +22 -4
- data/lib/vkontakte_api/error.rb +15 -7
- data/lib/vkontakte_api/logger.rb +35 -0
- data/lib/vkontakte_api/method.rb +40 -0
- data/lib/vkontakte_api/namespace.rb +7 -0
- data/lib/vkontakte_api/resolvable.rb +20 -0
- data/lib/vkontakte_api/resolver.rb +18 -103
- data/lib/vkontakte_api/result.rb +48 -0
- data/lib/vkontakte_api/uploading.rb +29 -0
- data/lib/vkontakte_api/utils.rb +28 -0
- data/lib/vkontakte_api/version.rb +2 -1
- data/lib/vkontakte_api.rb +14 -3
- data/spec/integration_spec.rb +84 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/vkontakte_api/api_spec.rb +39 -58
- data/spec/vkontakte_api/authorization_spec.rb +111 -0
- data/spec/vkontakte_api/client_spec.rb +17 -24
- data/spec/vkontakte_api/configuration_spec.rb +5 -0
- data/spec/vkontakte_api/error_spec.rb +30 -10
- data/spec/vkontakte_api/logger_spec.rb +88 -0
- data/spec/vkontakte_api/method_spec.rb +59 -0
- data/spec/vkontakte_api/namespace_spec.rb +5 -0
- data/spec/vkontakte_api/resolvable_spec.rb +21 -0
- data/spec/vkontakte_api/resolver_spec.rb +58 -141
- data/spec/vkontakte_api/result_spec.rb +115 -0
- data/spec/vkontakte_api/uploading_spec.rb +46 -0
- data/spec/vkontakte_api/utils_spec.rb +47 -0
- data/spec/vkontakte_api_spec.rb +4 -0
- data/vkontakte_api.gemspec +6 -5
- metadata +119 -38
- data/README.ru.md +0 -115
@@ -0,0 +1,35 @@
|
|
1
|
+
module VkontakteApi
|
2
|
+
# Faraday middleware for logging requests and responses.
|
3
|
+
#
|
4
|
+
# It's behaviour depends on the logging options in the configuration.
|
5
|
+
class Logger < Faraday::Response::Middleware
|
6
|
+
# Creates a middleware instance.
|
7
|
+
# The logger is set from `:logger` configuration option.
|
8
|
+
def initialize(app)
|
9
|
+
super(app)
|
10
|
+
@logger = VkontakteApi.logger
|
11
|
+
end
|
12
|
+
|
13
|
+
# Logs the request if needed.
|
14
|
+
# @param [Hash] env Request data.
|
15
|
+
def call(env)
|
16
|
+
if VkontakteApi.log_requests?
|
17
|
+
@logger.debug "#{env[:method].to_s.upcase} #{env[:url].to_s}"
|
18
|
+
end
|
19
|
+
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
# Logs the response (successful or not) if needed.
|
24
|
+
# @param [Hash] env Response data.
|
25
|
+
def on_complete(env)
|
26
|
+
if env[:body].error?
|
27
|
+
@logger.warn env[:raw_body] if VkontakteApi.log_errors?
|
28
|
+
else
|
29
|
+
@logger.debug env[:raw_body] if VkontakteApi.log_responses?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Faraday.register_middleware :response, :vk_logger => VkontakteApi::Logger
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module VkontakteApi
|
2
|
+
# An API method. It is responsible for generating it's full name and determining it's type.
|
3
|
+
class Method
|
4
|
+
include Resolvable
|
5
|
+
|
6
|
+
# A pattern for names of methods with a boolean result.
|
7
|
+
PREDICATE_NAMES = /^is.*\?$/
|
8
|
+
|
9
|
+
# Calling the API method.
|
10
|
+
# It delegates the network request to `API.call` and result processing to `Result.process`.
|
11
|
+
# @param [Hash] args Arguments for the API method.
|
12
|
+
def call(args = {}, &block)
|
13
|
+
response = API.call(full_name, args, token)
|
14
|
+
Result.process(response, type, block)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def full_name
|
19
|
+
parts = [@previous_resolver.name, @name].compact.map { |part| camelize(part) }
|
20
|
+
parts.join('.').gsub(/[^A-Za-z.]/, '')
|
21
|
+
end
|
22
|
+
|
23
|
+
def type
|
24
|
+
@name =~ PREDICATE_NAMES ? :boolean : :anything
|
25
|
+
end
|
26
|
+
|
27
|
+
# camelize('get_profiles')
|
28
|
+
# => 'getProfiles'
|
29
|
+
def camelize(name)
|
30
|
+
words = name.split('_')
|
31
|
+
first_word = words.shift
|
32
|
+
|
33
|
+
words.each do |word|
|
34
|
+
word.sub!(/^[a-z]/, &:upcase)
|
35
|
+
end
|
36
|
+
|
37
|
+
words.unshift(first_word).join
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VkontakteApi
|
2
|
+
# A mixin for classes that will be resolved via `#method_missing`.
|
3
|
+
module Resolvable
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
# Creates a resolvable object keeping it's name and the object that resolved it.
|
7
|
+
# @param [String] name The name of this resolvable.
|
8
|
+
# @option options [Hashie::Mash] :resolver A mash holding information about the previous resolver.
|
9
|
+
def initialize(name, options = {})
|
10
|
+
@name = name
|
11
|
+
@previous_resolver = options.delete(:resolver)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the token from the previous resolver.
|
15
|
+
# @return [String] A token.
|
16
|
+
def token
|
17
|
+
@previous_resolver.token
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,125 +1,40 @@
|
|
1
1
|
module VkontakteApi
|
2
|
-
# A
|
3
|
-
|
4
|
-
# Methods are dispatched the following way:
|
5
|
-
#
|
6
|
-
# 1. API client gets an unknown method, creates a `VkontakteApi::Resolver` instance and sends it the method
|
7
|
-
# 2. if the method is a namespace (like `friends`), it creates another `VkontakteApi::Resolver` instance, namespaced this time; else go to 3
|
8
|
-
# 3. the `VkontakteApi::Resolver` instance gets the last method, inserts an access token into params and sends it to `VkontakteApi::API`
|
9
|
-
# 4. the result is typecasted and/or yielded (mapped) to a block depending on it's type
|
10
|
-
class Resolver
|
11
|
-
# A pattern for names of methods with a boolean result.
|
12
|
-
PREDICATE_NAMES = /^(is.*)\?$/
|
13
|
-
|
14
|
-
# A namespace of the current instance (if present).
|
15
|
-
attr_reader :namespace
|
16
|
-
|
17
|
-
# A new resolver.
|
18
|
-
# @option options [String] :namespace A namespace.
|
19
|
-
# @option options [String] :access_token An access token.
|
20
|
-
def initialize(options = {})
|
21
|
-
@namespace = options.delete(:namespace)
|
22
|
-
@access_token = options.delete(:access_token)
|
23
|
-
end
|
24
|
-
|
2
|
+
# A mixin for classes that will resolve other classes' objects via `#method_missing`.
|
3
|
+
module Resolver
|
25
4
|
# Main methods dispatch.
|
26
5
|
#
|
27
|
-
# If the called method is a namespace, it creates and returns a new `VkontakteApi::
|
28
|
-
# Otherwise it
|
29
|
-
#
|
30
|
-
# If the result is enumerable, each element is yielded to the block (or returned as is if called without a block).
|
31
|
-
# Non-enumerable results are typecasted (and yielded if the block is present).
|
32
|
-
#
|
33
|
-
# Called with a block, it returns the result of the block; called without a block it returns just the result.
|
34
|
-
# @todo Break this crap into several small methods.
|
6
|
+
# If the called method is a namespace, it creates and returns a new `VkontakteApi::Namespace` instance.
|
7
|
+
# Otherwise it creates a `VkontakteApi::Method` instance and invokes it's `#call` method passing it the arguments and a block.
|
35
8
|
def method_missing(method_name, *args, &block)
|
36
9
|
method_name = method_name.to_s
|
37
10
|
|
38
11
|
if Resolver.namespaces.include?(method_name)
|
39
|
-
#
|
40
|
-
|
12
|
+
# called from Client
|
13
|
+
Namespace.new(method_name, :resolver => resolver)
|
41
14
|
else
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
args = args.first || {}
|
46
|
-
args[:access_token] = @access_token unless @access_token.nil?
|
47
|
-
|
48
|
-
result = API.call(name, args, &block)
|
49
|
-
|
50
|
-
if result.respond_to?(:each)
|
51
|
-
# enumerable result receives :map with a block when called with a block
|
52
|
-
# or is returned untouched otherwise
|
53
|
-
block_given? ? result.map(&block) : result
|
54
|
-
else
|
55
|
-
# non-enumerable result is typecasted
|
56
|
-
# (and yielded if block_given?)
|
57
|
-
result = typecast(result, type)
|
58
|
-
block_given? ? yield(result) : result
|
59
|
-
end
|
15
|
+
# called from Namespace or one-level method
|
16
|
+
Method.new(method_name, :resolver => resolver).call(args.first || {}, &block)
|
60
17
|
end
|
61
18
|
end
|
62
19
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# '1' becomes true, '0' becomes false
|
68
|
-
!parameter.to_i.zero?
|
69
|
-
else
|
70
|
-
parameter
|
71
|
-
end
|
20
|
+
# A `Hashie::Mash` structure holding the name and token of current instance.
|
21
|
+
# @return [Hashie::Mash]
|
22
|
+
def resolver
|
23
|
+
@resolver ||= Hashie::Mash.new(:name => @name, :token => token)
|
72
24
|
end
|
73
25
|
|
74
26
|
class << self
|
75
27
|
# An array of method namespaces.
|
28
|
+
# Lazily loads the list from `namespaces.yml` and caches it.
|
76
29
|
# @return [Array]
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
def load_namespaces
|
82
|
-
filename = File.expand_path('../namespaces.yml', __FILE__)
|
83
|
-
file = File.read(filename)
|
84
|
-
@namespaces = YAML.load(file)
|
85
|
-
end
|
86
|
-
|
87
|
-
# A complete method name needed by VKontakte.
|
88
|
-
#
|
89
|
-
# Returns a full name and the result type (:boolean or :anything).
|
90
|
-
# @example
|
91
|
-
# vk_method_name('is_app_user?')
|
92
|
-
# # => 'isAppUser'
|
93
|
-
# vk_method_name('get_country_by_id', 'places')
|
94
|
-
# # => 'places.getCountryById'
|
95
|
-
# @return [Array] full method name and type
|
96
|
-
def vk_method_name(method_name, namespace = nil)
|
97
|
-
method_name = method_name.to_s
|
98
|
-
|
99
|
-
if method_name =~ PREDICATE_NAMES
|
100
|
-
# predicate methods should return true or false
|
101
|
-
method_name.sub!(PREDICATE_NAMES, '\1')
|
102
|
-
type = :boolean
|
103
|
-
else
|
104
|
-
# other methods can return anything they want
|
105
|
-
type = :anything
|
30
|
+
def namespaces
|
31
|
+
if @namespaces.nil?
|
32
|
+
filename = File.expand_path('../namespaces.yml', __FILE__)
|
33
|
+
@namespaces = YAML.load_file(filename)
|
106
34
|
end
|
107
35
|
|
108
|
-
|
109
|
-
full_name << convert(namespace) + '.' unless namespace.nil?
|
110
|
-
full_name << convert(method_name)
|
111
|
-
|
112
|
-
[full_name, type]
|
113
|
-
end
|
114
|
-
|
115
|
-
private
|
116
|
-
# convert('get_profiles')
|
117
|
-
# => 'getProfiles'
|
118
|
-
def convert(name)
|
119
|
-
name.camelize(:lower)
|
36
|
+
@namespaces
|
120
37
|
end
|
121
38
|
end
|
122
39
|
end
|
123
40
|
end
|
124
|
-
|
125
|
-
VkontakteApi::Resolver.load_namespaces
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module VkontakteApi
|
2
|
+
# A module that handles method result processing.
|
3
|
+
#
|
4
|
+
# It implements method blocks support, result typecasting and raises `VkontakteApi::Error` in case of an error response.
|
5
|
+
module Result
|
6
|
+
class << self
|
7
|
+
# The main method result processing.
|
8
|
+
# @param [Hashie::Mash] response The server response in mash format.
|
9
|
+
# @param [Symbol] type The expected result type (`:boolean` or `:anything`).
|
10
|
+
# @param [Proc] block A block passed to the API method.
|
11
|
+
# @return [Array, Hashie::Mash] The processed result.
|
12
|
+
# @raise [VkontakteApi::Error] raised when VKontakte returns an error response.
|
13
|
+
def process(response, type, block)
|
14
|
+
result = extract_result(response)
|
15
|
+
|
16
|
+
if result.respond_to?(:each)
|
17
|
+
# enumerable result receives :map with a block when called with a block
|
18
|
+
# or is returned untouched otherwise
|
19
|
+
block.nil? ? result : result.map(&block)
|
20
|
+
else
|
21
|
+
# non-enumerable result is typecasted
|
22
|
+
# (and yielded if block_given?)
|
23
|
+
result = typecast(result, type)
|
24
|
+
block.nil? ? result : block.call(result)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def extract_result(response)
|
30
|
+
if response.error?
|
31
|
+
raise VkontakteApi::Error.new(response.error)
|
32
|
+
else
|
33
|
+
response.response
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def typecast(parameter, type)
|
38
|
+
case type
|
39
|
+
when :boolean
|
40
|
+
# '1' becomes true, '0' becomes false
|
41
|
+
!parameter.to_i.zero?
|
42
|
+
else
|
43
|
+
parameter
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module VkontakteApi
|
2
|
+
# A module implementing files uploading functionality.
|
3
|
+
#
|
4
|
+
# @note `VkontakteApi::Uploading` extends `VkontakteApi` so these methods should be called from the latter.
|
5
|
+
module Uploading
|
6
|
+
# Files uploading. It uses the same faraday middleware stack as API method calls (by using `VkontakteApi::API.connection`).
|
7
|
+
# @param [Hash] params A list of files to upload (also includes the upload URL). See example for the hash format.
|
8
|
+
# @option params [String] :url URL for the request.
|
9
|
+
# @return [Hashie::Mash] The server response.
|
10
|
+
# @raise [ArgumentError] raised when a `:url` parameter is omitted.
|
11
|
+
# @example
|
12
|
+
# VkontakteApi.upload(
|
13
|
+
# url: 'http://example.com/upload',
|
14
|
+
# file1: ['/path/to/file1.jpg', 'image/jpeg'],
|
15
|
+
# file2: ['/path/to/file2.png', 'image/png']
|
16
|
+
# )
|
17
|
+
def upload(params = {})
|
18
|
+
url = params.delete(:url)
|
19
|
+
raise ArgumentError, 'You should pass :url parameter' unless url
|
20
|
+
|
21
|
+
files = {}
|
22
|
+
params.each do |param_name, (file_path, file_type)|
|
23
|
+
files[param_name] = Faraday::UploadIO.new(file_path, file_type)
|
24
|
+
end
|
25
|
+
|
26
|
+
API.connection.post(url, files).body
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module VkontakteApi
|
2
|
+
# An utility module able to flatten arguments (join arrays into comma-separated strings).
|
3
|
+
module Utils
|
4
|
+
class << self
|
5
|
+
# A multiple version of `#flatten_argument`. It transforms a hash flattening each value and keeping the keys untouched.
|
6
|
+
# @param [Hash] arguments The arguments to flatten.
|
7
|
+
# @return [Hash] Flattened arguments.
|
8
|
+
def flatten_arguments(arguments)
|
9
|
+
arguments.inject({}) do |flat_args, (arg_name, arg_value)|
|
10
|
+
flat_args[arg_name] = flatten_argument(arg_value)
|
11
|
+
flat_args
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# If an argument is an array, it will be joined with a comma; otherwise it'll be returned untouched.
|
16
|
+
# @param [Object] argument The argument to flatten.
|
17
|
+
def flatten_argument(argument)
|
18
|
+
if argument.respond_to?(:join)
|
19
|
+
# if argument is an array, we join it with a comma
|
20
|
+
argument.join(',')
|
21
|
+
else
|
22
|
+
# otherwise leave it untouched
|
23
|
+
argument
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/vkontakte_api.rb
CHANGED
@@ -1,19 +1,30 @@
|
|
1
1
|
require 'faraday'
|
2
|
-
require '
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'faraday_middleware/parse_oj'
|
4
|
+
require 'oauth2'
|
3
5
|
require 'yaml'
|
4
|
-
require '
|
5
|
-
require 'active_support/core_ext/object/to_query'
|
6
|
+
require 'hashie'
|
6
7
|
|
7
8
|
require 'vkontakte_api/version'
|
8
9
|
require 'vkontakte_api/error'
|
9
10
|
require 'vkontakte_api/configuration'
|
11
|
+
require 'vkontakte_api/authorization'
|
12
|
+
require 'vkontakte_api/uploading'
|
13
|
+
require 'vkontakte_api/utils'
|
10
14
|
require 'vkontakte_api/api'
|
11
15
|
require 'vkontakte_api/resolver'
|
16
|
+
require 'vkontakte_api/resolvable'
|
12
17
|
require 'vkontakte_api/client'
|
18
|
+
require 'vkontakte_api/namespace'
|
19
|
+
require 'vkontakte_api/method'
|
20
|
+
require 'vkontakte_api/result'
|
21
|
+
require 'vkontakte_api/logger'
|
13
22
|
|
14
23
|
# Main module.
|
15
24
|
module VkontakteApi
|
16
25
|
extend VkontakteApi::Configuration
|
26
|
+
extend VkontakteApi::Authorization
|
27
|
+
extend VkontakteApi::Uploading
|
17
28
|
end
|
18
29
|
|
19
30
|
# short alias
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe "Integration" do
|
5
|
+
before(:all) do
|
6
|
+
# turn off all the logging
|
7
|
+
VkontakteApi.configure do |config|
|
8
|
+
config.log_requests = false
|
9
|
+
config.log_errors = false
|
10
|
+
config.log_responses = false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "unauthorized requests" do
|
15
|
+
before(:each) do
|
16
|
+
@vk = VkontakteApi::Client.new
|
17
|
+
end
|
18
|
+
|
19
|
+
it "get users" do
|
20
|
+
user = @vk.users.get(:uid => 1).first
|
21
|
+
user.uid.should == 1
|
22
|
+
user.last_name.should == 'Дуров'
|
23
|
+
user.first_name.should == 'Павел'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "authorized requests" do
|
28
|
+
before(:each) do
|
29
|
+
@vk = VkontakteApi::Client.new(ENV['TOKEN'])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "get groups" do
|
33
|
+
groups = @vk.groups.get
|
34
|
+
groups.should include(1)
|
35
|
+
end
|
36
|
+
end if ENV['TOKEN']
|
37
|
+
|
38
|
+
describe "requests with camelCase and predicate methods" do
|
39
|
+
before(:each) do
|
40
|
+
@vk = VkontakteApi::Client.new(ENV['TOKEN'])
|
41
|
+
end
|
42
|
+
|
43
|
+
it "convert method names to vk.com format" do
|
44
|
+
@vk.is_app_user?.should be_true
|
45
|
+
end
|
46
|
+
end if ENV['TOKEN']
|
47
|
+
|
48
|
+
describe "requests with array arguments" do
|
49
|
+
before(:each) do
|
50
|
+
@vk = VkontakteApi::Client.new
|
51
|
+
end
|
52
|
+
|
53
|
+
it "join arrays with a comma" do
|
54
|
+
users = @vk.users.get(:uids => [1, 2, 3], :fields => %w[first_name last_name screen_name])
|
55
|
+
users.first.screen_name.should == 'durov'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "requests with blocks" do
|
60
|
+
before(:each) do
|
61
|
+
@vk = VK::Client.new
|
62
|
+
end
|
63
|
+
|
64
|
+
it "map the result with a block" do
|
65
|
+
users = @vk.users.get(:uid => 1) do |user|
|
66
|
+
"#{user.last_name} #{user.first_name}"
|
67
|
+
end
|
68
|
+
|
69
|
+
users.first.should == 'Дуров Павел'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "authorization" do
|
74
|
+
context "with a scope" do
|
75
|
+
it "returns a correct url" do
|
76
|
+
VkontakteApi.authorization_url(:scope => %w[friends groups]).should include('scope=friends%2Cgroups')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
after(:all) do
|
82
|
+
VkontakteApi.reset
|
83
|
+
end
|
84
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,2 +1,20 @@
|
|
1
1
|
require 'vkontakte_api'
|
2
2
|
require 'pry'
|
3
|
+
|
4
|
+
RSpec::Matchers.define :log_requests do
|
5
|
+
match do |logger|
|
6
|
+
logger.log_requests?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec::Matchers.define :log_errors do
|
11
|
+
match do |logger|
|
12
|
+
logger.log_errors?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec::Matchers.define :log_responses do
|
17
|
+
match do |logger|
|
18
|
+
logger.log_responses?
|
19
|
+
end
|
20
|
+
end
|
@@ -1,81 +1,62 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe VkontakteApi::API do
|
4
|
-
|
5
|
-
@
|
6
|
-
|
7
|
-
|
8
|
-
:
|
9
|
-
|
4
|
+
def create_connection
|
5
|
+
@result = {'response' => {'key' => 'value'}}
|
6
|
+
|
7
|
+
@connection = Faraday.new do |builder|
|
8
|
+
builder.response :mashify
|
9
|
+
builder.response :json, :preserve_raw => true
|
10
|
+
builder.adapter :test do |stub|
|
11
|
+
stub.get('/apiMethod') do
|
12
|
+
[200, {}, Oj.dump(@result)]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
subject.stub(:connection).and_return(@connection)
|
10
17
|
end
|
11
18
|
|
12
19
|
describe ".call" do
|
13
20
|
before(:each) do
|
14
|
-
|
15
|
-
VkontakteApi::API.stub(:url_for).and_return(@url)
|
16
|
-
|
17
|
-
@connection = stub("Faraday connection")
|
18
|
-
Faraday.stub(:new).and_return(@connection)
|
19
|
-
|
20
|
-
body = stub("Response body")
|
21
|
-
response = stub("Response", :body => body)
|
22
|
-
@connection.stub(:get).and_return(response)
|
23
|
-
|
24
|
-
@result = stub("Result")
|
25
|
-
@result.stub(:has_key?) { |key| key == 'response' }
|
26
|
-
|
27
|
-
@result_response = stub("Result[response]")
|
28
|
-
@result_error = stub("Result[error]").as_null_object
|
29
|
-
|
30
|
-
@result.stub(:[]) do |key|
|
31
|
-
if key == :response
|
32
|
-
@result_response
|
33
|
-
else
|
34
|
-
@result_error
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
Yajl::Parser.stub(:parse).and_return(@result)
|
39
|
-
end
|
40
|
-
|
41
|
-
it "calls the url from .url_for" do
|
42
|
-
@connection.should_receive(:get).with(@url)
|
43
|
-
VkontakteApi::API.call('apiMethod')
|
21
|
+
create_connection
|
44
22
|
end
|
45
23
|
|
46
|
-
context "with a
|
47
|
-
it "
|
48
|
-
VkontakteApi::API
|
24
|
+
context "called with a token parameter" do
|
25
|
+
it "sends it to .connection" do
|
26
|
+
subject.should_receive(:connection).with(:url => VkontakteApi::API::URL_PREFIX, :token => 'token')
|
27
|
+
subject.call('apiMethod', {:some => :params}, 'token')
|
49
28
|
end
|
50
29
|
end
|
51
30
|
|
52
|
-
|
53
|
-
|
54
|
-
@result.stub(:has_key?) { |key| key != 'response' }
|
55
|
-
end
|
56
|
-
|
57
|
-
it "raises a VkontakteApi::Error" do
|
58
|
-
expect {
|
59
|
-
VkontakteApi::API.call('apiMethod')
|
60
|
-
}.to raise_error(VkontakteApi::Error)
|
61
|
-
end
|
31
|
+
it "returns the response body" do
|
32
|
+
subject.call('apiMethod').should == @result
|
62
33
|
end
|
63
34
|
end
|
64
35
|
|
65
|
-
describe ".
|
66
|
-
it "
|
67
|
-
url =
|
68
|
-
url
|
36
|
+
describe ".connection" do
|
37
|
+
it "uses the :url parameter" do
|
38
|
+
url = stub("URL")
|
39
|
+
Faraday.should_receive(:new).with(url)
|
40
|
+
connection = subject.connection(:url => url)
|
41
|
+
end
|
42
|
+
|
43
|
+
context "without a token" do
|
44
|
+
it "creates a connection without an oauth2 middleware" do
|
45
|
+
connection = subject.connection
|
46
|
+
connection.builder.handlers.map(&:name).should_not include('FaradayMiddleware::OAuth2')
|
47
|
+
end
|
69
48
|
end
|
70
49
|
|
71
|
-
context "with
|
50
|
+
context "with a token" do
|
72
51
|
before(:each) do
|
73
|
-
@
|
52
|
+
@token = stub("Token")
|
74
53
|
end
|
75
54
|
|
76
|
-
it "
|
77
|
-
|
78
|
-
|
55
|
+
it "creates a connection with an oauth2 middleware" do
|
56
|
+
connection = subject.connection(:token => @token)
|
57
|
+
handler = connection.builder.handlers.first
|
58
|
+
handler.name.should == 'FaradayMiddleware::OAuth2'
|
59
|
+
handler.instance_variable_get(:@args).should == [@token]
|
79
60
|
end
|
80
61
|
end
|
81
62
|
end
|