vkontakte_api 0.1

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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ # Specify your gem's dependencies in vkontakte_api.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Vsevolod Romashov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,95 @@
1
+ # vkontakte_api
2
+
3
+ `vkontakte_api` is a Ruby wrapper for VKontakte API. It allows you to call all API methods in the simplest possible way.
4
+
5
+ Below is the English version of the readme. Russian version is located [here](https://github.com/7even/vkontakte_api/blob/master/README.ru.md).
6
+
7
+ ## Installation
8
+
9
+ ``` bash
10
+ gem install vkontakte_api
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Default HTTP request library is `Net::HTTP`. You can set any other adapter supported by `faraday` in the configure block like so:
16
+
17
+ ``` ruby
18
+ VkontakteApi.configure do |config|
19
+ config.adapter = :net_http
20
+ end
21
+ ```
22
+
23
+ All requests are sent via `VkontakteApi::Client` instance. To create one you just pass an access token.
24
+
25
+ ``` ruby
26
+ @app = VkontakteApi::Client.new('my_access_token')
27
+ ```
28
+
29
+ Probably the easiest way to get an access token in a web-app is using [OmniAuth](https://github.com/intridea/omniauth), but you can roll your own authentication if for some reason `OmniAuth` isn't acceptable. Currently `vkontakte_api` doesn't offer authentication functionality.
30
+
31
+ Now you can call the API methods. All method names are underscore_cased as opposed to the [official documentation](http://vk.com/developers.php?oid=-17680044&p=API_Method_Description) where they are camelCased, so `getGroups` becomes `get_groups`. You can still call them in a camelCased manner, but that is not a Ruby-way practice.
32
+
33
+ ``` ruby
34
+ @app.get_user_settings # => 327710
35
+ @app.groups.get # => [1, 31022447]
36
+ ```
37
+
38
+ Predicate methods (those which begin with `is`, like `is_app_user`) are expected to return the result of some condition, so the '?' is appended to the end of the method name, and they return `true` or `false`:
39
+
40
+ ``` ruby
41
+ @app.is_app_user? # => true
42
+ ```
43
+
44
+ You can still call these without a '?' and get `'1'` or `'0'` in result if you want to handle that yourself.
45
+
46
+ Now for parameters. All method parameters are named, and you can pass them in a hash where parameter names are keys and parameter values are values:
47
+
48
+ ``` ruby
49
+ @app.friends.get(fields: 'uid,first_name,last_name')
50
+ # => [
51
+ {
52
+ :uid => "1",
53
+ :first_name => "Павел",
54
+ :last_name => "Дуров"
55
+ },
56
+ {
57
+ :uid => "6492",
58
+ :first_name => "Andrew",
59
+ :last_name => "Rogozov"
60
+ }
61
+ ]
62
+ ```
63
+
64
+ It's also worth noting that all returned hashes have symbolized keys.
65
+
66
+ If the response is an Enumerable, you can pass a block that will yield each successive element and put the result in the returned array (like `Enumerable#map` does):
67
+
68
+ ``` ruby
69
+ @app.friends.get(fields: 'first_name,last_name') do |friend|
70
+ "#{friend[:first_name]} #{friend[:last_name]}"
71
+ end
72
+ # => ["Павел Дуров", "Andrew Rogozov"]
73
+ ```
74
+
75
+ `vkontakte_api` doesn't keep any method names list inside (except method namespaces like `friends` or `groups`) - when you call a method, it's name is camelcased before sending a request to VKontakte. So when a new method is added to the API, you don't need to wait for the new version of `vkontakte_api` gem - you can use that new method immediately. If you mistype the method name or use a method you don't have rights to call, you will get an exception with a relevant message (more about the exceptions below).
76
+
77
+ ### Error handling
78
+
79
+ If VKontakte returns an error in response, you get a `VkontakteApi::Error` exception with all meaningful information that can be retrieved:
80
+
81
+ ``` ruby
82
+ @app.audio.get_by_id
83
+ # => VkontakteApi::Error: VKontakte returned an error 1: 'Unknown error occured' after calling method 'audio.getById' with parameters {}.
84
+ ```
85
+
86
+ ## Roadmap
87
+
88
+ * Authentication (getting the access_token from VK)
89
+ * RDoc coverage
90
+
91
+ ## Contributing
92
+
93
+ If you want to contribute to the project, fork the repository, push your changes to a topic branch and send me a pull request.
94
+
95
+ `vkontakte_api` is tested under MRI `1.8.7`, `1.9.2` and `1.9.3`. If something is working incorrectly or not working at all in one of these environments, this should be considered a bug. Any bug reports are welcome at Github issues.
@@ -0,0 +1,95 @@
1
+ # vkontakte_api
2
+
3
+ `vkontakte_api` - ruby-обертка для API ВКонтакте. Она позволяет вызывать методы API настолько просто, насколько это возможно.
4
+
5
+ Это русская версия readme. Английская версия лежит [здесь](https://github.com/7even/vkontakte_api/blob/master/README.md).
6
+
7
+ ## Установка
8
+
9
+ ``` bash
10
+ gem install vkontakte_api
11
+ ```
12
+
13
+ ## Использование
14
+
15
+ По умолчанию для HTTP-запросов используется `Net::HTTP`. Можно выбрать любой другой адаптер, поддерживаемый `faraday`, в блоке `VkontakteApi.configure` следующим образом:
16
+
17
+ ``` ruby
18
+ VkontakteApi.configure do |config|
19
+ config.adapter = :net_http
20
+ end
21
+ ```
22
+
23
+ Все запросы к API отправляются через объект класса `VkontakteApi::Client`. Чтобы создать его, нужно просто передать в конструктор токен доступа.
24
+
25
+ ``` ruby
26
+ @app = VkontakteApi::Client.new('my_access_token')
27
+ ```
28
+
29
+ Пожалуй, самый простой способ получить токен в веб-приложении - использовать [OmniAuth](https://github.com/intridea/omniauth), но если это неприемлемо, можно реализовать свой механизм авторизации. На данный момент `vkontakte_api` не умеет получать токен.
30
+
31
+ Теперь можно вызывать методы API. Все названия методов переведены в underscore_case - в отличие от [официальной документации](http://vk.com/developers.php?oid=-17680044&p=API_Method_Description), где они в camelCase, т.е. `getGroups` становится `get_groups`. Можно по прежнему писать методы в camelCase, но это не соответствует стандартам стиля кода, принятым в ruby.
32
+
33
+ ``` ruby
34
+ @app.get_user_settings # => 327710
35
+ @app.groups.get # => [1, 31022447]
36
+ ```
37
+
38
+ Предикатные методы (названия которых начинаются с `is`, например `is_app_user`) должны возвращать результат какого-то условия, поэтому в конец названия метода добавляется '?', и возвращается булево значение (`true` или `false`):
39
+
40
+ ``` ruby
41
+ @app.is_app_user? # => true
42
+ ```
43
+
44
+ Можно вызывать эти методы и без '?' на конце, тогда они будут возвращать `'0'` или `'1'`.
45
+
46
+ Теперь о параметрах. Все параметры именованные, и передаются в методы в виде хэша, где ключи соответствуют названиям параметров, а значения - соответственно, их значениям:
47
+
48
+ ``` ruby
49
+ @app.friends.get(fields: 'uid,first_name,last_name')
50
+ # => [
51
+ {
52
+ :uid => "1",
53
+ :first_name => "Павел",
54
+ :last_name => "Дуров"
55
+ },
56
+ {
57
+ :uid => "6492",
58
+ :first_name => "Andrew",
59
+ :last_name => "Rogozov"
60
+ }
61
+ ]
62
+ ```
63
+
64
+ Также следует заметить, что все возвращаемые хэши имеют символьные ключи.
65
+
66
+ Если результат метода - Enumerable, то методу можно передать блок, который будет вызван для каждого элемента результата. В этом случае метод вернет массив из результатов выполнения блока с каждым элементом (аналогично `Enumerable#map`):
67
+
68
+ ``` ruby
69
+ @app.friends.get(fields: 'first_name,last_name') do |friend|
70
+ "#{friend[:first_name]} #{friend[:last_name]}"
71
+ end
72
+ # => ["Павел Дуров", "Andrew Rogozov"]
73
+ ```
74
+
75
+ `vkontakte_api` не содержит списка названий методов (если не считать пространств имен, вроде `friends` или `groups`) - когда вызывается метод, его название переводится в camelCase, а уже потом отправляется запрос к ВКонтакте. Поэтому когда новый метод добавляется в API, не нужно ждать новой версии гема `vkontakte_api` - можно использовать этот новый метод сразу же. Если в названии запрошенного метода допущены ошибки, или вызван метод, на выполнение которого отсутствуют права, будет выброшено исключение с соответствующим сообщением (об исключениях чуть ниже).
76
+
77
+ ### Обработка ошибок
78
+
79
+ Если ВКонтакте возвращает ошибку, выбрасывается исключение класса `VkontakteApi::Error` со всей значимой информацией, которую можно получить:
80
+
81
+ ``` ruby
82
+ @app.audio.get_by_id
83
+ # => VkontakteApi::Error: VKontakte returned an error 1: 'Unknown error occured' after calling method 'audio.getById' with parameters {}.
84
+ ```
85
+
86
+ ## Планы
87
+
88
+ * Авторизация (получение токена доступа с ВКонтакте)
89
+ * Документация RDoc
90
+
91
+ ## Участие в разработке
92
+
93
+ Если вы хотите поучаствовать в разработке проекта, форкните репозиторий, положите свои изменения в отдельную ветку и отправьте мне pull request.
94
+
95
+ `vkontakte_api` тестируется под MRI `1.8.7`, `1.9.2` и `1.9.3`. Если в одной из этих сред что-то работает неправильно, либо вообще не работает, то это следует считать багом, и написать об этом в issues на Github.
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ desc 'Fires up the console with preloaded vkontakte_api'
4
+ task :console do
5
+ sh 'pry -I ./lib/ -r ./lib/vkontakte_api.rb'
6
+ end
7
+
8
+ require 'rspec/core/rake_task'
9
+ RSpec::Core::RakeTask.new do |t|
10
+ t.rspec_opts = '--color --format doc'
11
+ end
12
+
13
+ task :default => :spec
@@ -0,0 +1,19 @@
1
+ require 'faraday'
2
+ require 'yajl'
3
+ require 'yaml'
4
+ require 'active_support/core_ext/string/inflections'
5
+ require 'active_support/core_ext/object/to_query'
6
+
7
+ require 'vkontakte_api/version'
8
+ require 'vkontakte_api/error'
9
+ require 'vkontakte_api/configuration'
10
+ require 'vkontakte_api/api'
11
+ require 'vkontakte_api/resolver'
12
+ require 'vkontakte_api/client'
13
+
14
+ module VkontakteApi
15
+ extend VkontakteApi::Configuration
16
+ end
17
+
18
+ # short alias
19
+ VK = VkontakteApi unless defined?(VK)
@@ -0,0 +1,28 @@
1
+ module VkontakteApi
2
+ module API
3
+ BASE_HOST = 'https://api.vkontakte.ru'
4
+ BASE_URL = '/method/'
5
+
6
+ class << self
7
+ def call(method_name, args = {}, &block)
8
+ connection = Faraday.new(:url => BASE_HOST) do |builder|
9
+ builder.adapter(VkontakteApi.adapter)
10
+ end
11
+
12
+ url = url_for(method_name, args)
13
+ body = connection.get(url).body
14
+ response = Yajl::Parser.parse(body, :symbolize_keys => true)
15
+
16
+ if response.has_key?(:error)
17
+ raise VkontakteApi::Error.new(response[:error])
18
+ else
19
+ response[:response]
20
+ end
21
+ end
22
+ private
23
+ def url_for(method_name, args)
24
+ "#{BASE_URL}#{method_name}?#{args.to_param}"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module VkontakteApi
2
+ class Client
3
+ attr_reader :access_token
4
+
5
+ def initialize(access_token = nil)
6
+ @access_token = access_token
7
+ end
8
+
9
+ def authorized?
10
+ !@access_token.nil?
11
+ end
12
+
13
+ def method_missing(method_name, *args, &block)
14
+ args = args.first || {}
15
+ VkontakteApi::Resolver.new(:access_token => @access_token).send(method_name, args, &block)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module VkontakteApi
2
+ module Configuration
3
+ OPTION_NAMES = [:app_id, :app_secret, :adapter]
4
+
5
+ attr_accessor *OPTION_NAMES
6
+
7
+ DEFAULT_ADAPTER = :net_http
8
+
9
+ def configure
10
+ yield self if block_given?
11
+ self
12
+ end
13
+
14
+ def reset
15
+ @adapter = DEFAULT_ADAPTER
16
+ end
17
+
18
+ def self.extended(base)
19
+ base.reset
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ module VkontakteApi
2
+ class Error < StandardError
3
+ def initialize(data)
4
+ @error_code = data.delete(:error_code)
5
+ @error_msg = data.delete(:error_msg)
6
+ @params = {}
7
+
8
+ request_params = parse_params(data.delete :request_params)
9
+
10
+ @method_name = request_params.delete('method')
11
+ @access_token = request_params.delete('access_token')
12
+ @oauth = request_params.delete('oauth')
13
+ @params = request_params
14
+ end
15
+
16
+ def message
17
+ "VKontakte returned an error #{@error_code}: \'#{@error_msg}\' after calling method \'#{@method_name}\' with parameters #{@params.inspect}."
18
+ end
19
+ private
20
+ def parse_params(params)
21
+ params.inject({}) do |memo, pair|
22
+ memo[pair[:key]] = pair[:value]
23
+ memo
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ - friends
2
+ - groups
3
+ - photos
4
+ - wall
5
+ - newsfeed
6
+ - notifications
7
+ - audio
8
+ - video
9
+ - docs
10
+ - places
11
+ - secure
12
+ - storage
13
+ - notes
14
+ - pages
15
+ - activity
16
+ - offers
17
+ - questions
18
+ - subscriptions
19
+ - messages
20
+ - likes
21
+ - status
22
+ - polls
@@ -0,0 +1,91 @@
1
+ module VkontakteApi
2
+ class Resolver
3
+ PREDICATE_NAMES = /^(is.*)\?$/
4
+
5
+ attr_reader :namespace
6
+
7
+ def initialize(options = {})
8
+ @namespace = options.delete(:namespace)
9
+ @access_token = options.delete(:access_token)
10
+ end
11
+
12
+ def method_missing(method_name, *args, &block)
13
+ method_name = method_name.to_s
14
+
15
+ if Resolver.namespaces.include?(method_name)
16
+ # method with a two-level name called
17
+ Resolver.new(:namespace => method_name, :access_token => @access_token)
18
+ else
19
+ # method with a one-level name called
20
+ name, type = Resolver.vk_method_name(method_name, @namespace)
21
+
22
+ # adding access_token to the args hash
23
+ args = args.first || {}
24
+ args.update(:access_token => @access_token)
25
+
26
+ result = API.call(name, args, &block)
27
+
28
+ if result.respond_to?(:each)
29
+ # enumerable result receives :map with a block when called with a block
30
+ # or is returned untouched otherwise
31
+ block_given? ? result.map(&block) : result
32
+ else
33
+ # non-enumerable result is typecasted
34
+ # (and yielded if block_given?)
35
+ result = typecast(result, type)
36
+ block_given? ? yield(result) : result
37
+ end
38
+ end
39
+ end
40
+ private
41
+ def typecast(parameter, type)
42
+ case type
43
+ when :boolean
44
+ # '1' becomes true, '0' becomes false
45
+ !parameter.to_i.zero?
46
+ else
47
+ parameter
48
+ end
49
+ end
50
+
51
+ class << self
52
+ attr_reader :namespaces
53
+
54
+ # load namespaces array from namespaces.yml
55
+ def load_namespaces
56
+ filename = File.expand_path('../namespaces.yml', __FILE__)
57
+ file = File.read(filename)
58
+ @namespaces = YAML.load(file)
59
+ end
60
+
61
+ # vk_method_name('get_country_by_id', 'places')
62
+ # => 'places.getCountryById'
63
+ def vk_method_name(method_name, namespace = nil)
64
+ method_name = method_name.to_s
65
+
66
+ if method_name =~ PREDICATE_NAMES
67
+ # predicate methods should return true or false
68
+ method_name.sub!(PREDICATE_NAMES, '\1')
69
+ type = :boolean
70
+ else
71
+ # other methods can return anything they want
72
+ type = :anything
73
+ end
74
+
75
+ full_name = ''
76
+ full_name << convert(namespace) + '.' unless namespace.nil?
77
+ full_name << convert(method_name)
78
+
79
+ [full_name, type]
80
+ end
81
+ private
82
+ # convert('get_profiles')
83
+ # => 'getProfiles'
84
+ def convert(name)
85
+ name.camelize(:lower)
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ VkontakteApi::Resolver.load_namespaces
@@ -0,0 +1,3 @@
1
+ module VkontakteApi
2
+ VERSION = '0.1'
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'vkontakte_api'
2
+ require 'pry'
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe VkontakteApi::API do
4
+ before(:each) do
5
+ @method_name = 'apiMethod'
6
+ @args = {
7
+ :field => 'value',
8
+ :access_token => 'some_token'
9
+ }
10
+ end
11
+
12
+ describe ".call" do
13
+ before(:each) do
14
+ @url = stub("URL")
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?) do |key|
26
+ if key == 'response'
27
+ true
28
+ else
29
+ false
30
+ end
31
+ end
32
+
33
+ @result_response = stub("Result[response]")
34
+ @result_error = stub("Result[error]").as_null_object
35
+
36
+ @result.stub(:[]) do |key|
37
+ if key == :response
38
+ @result_response
39
+ else
40
+ @result_error
41
+ end
42
+ end
43
+
44
+ Yajl::Parser.stub(:parse).and_return(@result)
45
+ end
46
+
47
+ it "calls the url from .url_for" do
48
+ @connection.should_receive(:get).with(@url)
49
+ VkontakteApi::API.call('apiMethod')
50
+ end
51
+
52
+ context "with a successful response" do
53
+ it "returns the response body" do
54
+ VkontakteApi::API.call('apiMethod').should == @result_response
55
+ end
56
+ end
57
+
58
+ context "with an error response" do
59
+ before(:each) do
60
+ @result.stub(:has_key?) do |key|
61
+ if key == 'response'
62
+ false
63
+ else
64
+ true
65
+ end
66
+ end
67
+ end
68
+
69
+ it "raises a VkontakteApi::Error" do
70
+ expect {
71
+ VkontakteApi::API.call('apiMethod')
72
+ }.to raise_error(VkontakteApi::Error)
73
+ end
74
+ end
75
+ end
76
+
77
+ describe ".url_for" do
78
+ it "constructs a valid VK API url" do
79
+ url = VkontakteApi::API.send(:url_for, @method_name, @args)
80
+ url.should == '/method/apiMethod?access_token=some_token&field=value'
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe VkontakteApi::Client do
4
+ before(:each) do
5
+ @token = stub("Access token")
6
+ end
7
+
8
+ describe "#initialize" do
9
+ context "without arguments" do
10
+ it "creates a client with a nil access_token" do
11
+ VkontakteApi::Client.new.access_token.should be_nil
12
+ end
13
+ end
14
+
15
+ context "with a token argument" do
16
+ it "creates a client with a given access_token" do
17
+ client = VkontakteApi::Client.new(@token)
18
+ client.access_token.should == @token
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "#authorized?" do
24
+ context "with an unauthorized client" do
25
+ it "returns false" do
26
+ VkontakteApi::Client.new.should_not be_authorized
27
+ end
28
+ end
29
+
30
+ context "with an authorized client" do
31
+ it "returns true" do
32
+ VkontakteApi::Client.new(@token).should be_authorized
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "#method_missing" do
38
+ before(:each) do
39
+ @resolver = stub("Resolver").as_null_object
40
+ VkontakteApi::Resolver.stub(:new).and_return(@resolver)
41
+ @args = {:field => 'value'}
42
+ end
43
+
44
+ it "creates a resolver, passing it the access_token" do
45
+ VkontakteApi::Resolver.should_receive(:new).with(:access_token => @token)
46
+ VkontakteApi::Client.new(@token).api_method(@args)
47
+ end
48
+
49
+ it "delegates to VkontakteApi::Resolver" do
50
+ @resolver.should_receive(:api_method).with(@args)
51
+ VkontakteApi::Client.new(@token).api_method(@args)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ class Configurable
4
+ extend VkontakteApi::Configuration
5
+ end
6
+
7
+ describe VkontakteApi::Configuration do
8
+ describe "#configure" do
9
+ it "yields self" do
10
+ Configurable.should_receive(:some_method)
11
+ Configurable.configure do |config|
12
+ config.some_method
13
+ end
14
+ end
15
+
16
+ it "returns self" do
17
+ Configurable.configure.should == Configurable
18
+ end
19
+ end
20
+
21
+ describe "#reset" do
22
+ it "sets all options to their default values" do
23
+ Configurable.reset
24
+ Configurable.app_id.should be_nil
25
+ Configurable.app_secret.should be_nil
26
+ Configurable.adapter.should == VkontakteApi::Configuration::DEFAULT_ADAPTER
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe VkontakteApi::Error do
4
+ before(:each) do
5
+ @e = VkontakteApi::Error.new(
6
+ :error_code => 5,
7
+ :error_msg => 'User authorization failed: invalid access_token.',
8
+ :request_params => [
9
+ {
10
+ :key => 'oauth',
11
+ :value => '1'
12
+ },
13
+ {
14
+ :key => 'method',
15
+ :value => 'unknownMethod'
16
+ },
17
+ {
18
+ :key => 'some',
19
+ :value => 'params'
20
+ },
21
+ {
22
+ :key => 'access_token',
23
+ :value => '123'
24
+ }
25
+ ]
26
+ )
27
+ end
28
+
29
+ describe "#message" do
30
+ it "returns all needed data about an error" do
31
+ message = 'VKontakte returned an error 5: \'User authorization failed: invalid access_token.\' after calling method \'unknownMethod\' with parameters {"some"=>"params"}.'
32
+ expect {
33
+ raise @e
34
+ }.to raise_error(@e.class, message)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,169 @@
1
+ require 'spec_helper'
2
+
3
+ describe VkontakteApi::Resolver do
4
+ describe "#method_missing" do
5
+ before(:each) do
6
+ @result = stub("API result")
7
+ @result.stub(:respond_to?).and_return(false)
8
+
9
+ VkontakteApi::API.stub(:call).and_return(@result)
10
+ @args = {:arg_name => 'arg_value'}
11
+ @token = stub("Access token")
12
+ end
13
+
14
+ context "with a nil @namespace" do
15
+ before(:each) do
16
+ @resolver = VkontakteApi::Resolver.new(:access_token => @token)
17
+ end
18
+
19
+ context "with method_name not from NAMESPACES" do
20
+ before(:each) do
21
+ VkontakteApi::Resolver.stub(:vk_method_name).and_return(['apiMethod', :anything])
22
+ end
23
+
24
+ it "calls #vk_method_name with method name and nil namespace" do
25
+ VkontakteApi::Resolver.should_receive(:vk_method_name).with('api_method', nil)
26
+ @resolver.api_method
27
+ end
28
+
29
+ it "calls #api_call with full VK method name" do
30
+ full_args = @args.merge(:access_token => @token)
31
+ VkontakteApi::API.should_receive(:call).with('apiMethod', full_args)
32
+ @resolver.api_method(@args).should == @result
33
+ end
34
+ end
35
+
36
+ context "with method_name from NAMESPACES" do
37
+ it "return a new resolver with the corresponding @namespace" do
38
+ new_resolver = @resolver.friends
39
+ new_resolver.should be_a(VkontakteApi::Resolver)
40
+ new_resolver.namespace.should == 'friends'
41
+ end
42
+ end
43
+ end
44
+
45
+ context "with a non-nil @namespace" do
46
+ before(:each) do
47
+ @resolver = VkontakteApi::Resolver.new(:namespace => 'friends')
48
+ VkontakteApi::Resolver.stub(:vk_method_name).and_return('friends.apiMethod')
49
+ end
50
+
51
+ it "calls #vk_method_name with method name and @namespace" do
52
+ VkontakteApi::Resolver.should_receive(:vk_method_name).with('api_method', 'friends')
53
+ @resolver.api_method
54
+ end
55
+ end
56
+
57
+ context "with a non-enumerable result" do
58
+ before(:each) do
59
+ @resolver = VkontakteApi::Resolver.new
60
+
61
+ @type = stub("Type")
62
+ VkontakteApi::Resolver.stub(:vk_method_name).and_return([:method_name, @type])
63
+
64
+ @typecasted_value = stub("Typecasted value")
65
+ @resolver.stub(:typecast).and_return(@typecasted_value)
66
+ end
67
+
68
+ it "returns #typecast-ed value" do
69
+ @resolver.should_receive(:typecast).with(@result, @type).and_return(@typecasted_value)
70
+ @resolver.method_name.should == @typecasted_value
71
+ end
72
+
73
+ context "when block_given?" do
74
+ it "yields the #typecast-ed value and returns the result of the block" do
75
+ block_result = stub("Block result")
76
+ @typecasted_value.should_receive(:result_method).and_return(block_result)
77
+
78
+ @resolver.api_method do |result|
79
+ result.result_method
80
+ end.should == block_result
81
+ end
82
+ end
83
+ end
84
+
85
+ context "with an enumerable result" do
86
+ before(:each) do
87
+ @resolver = VkontakteApi::Resolver.new
88
+
89
+ @element1 = stub("First element")
90
+ @element2 = stub("Second element")
91
+ @enumerable_result = [@element1, @element2]
92
+ VkontakteApi::API.stub(:call).and_return(@enumerable_result)
93
+ end
94
+
95
+ it "returns the untouched value" do
96
+ @resolver.method_name.should == @enumerable_result
97
+ end
98
+
99
+ context "when block_given?" do
100
+ it "yields each element untouched to the block" do
101
+ result1 = stub("First element after result_method")
102
+ result2 = stub("Second element after result_method")
103
+ @element1.should_receive(:result_method).and_return(result1)
104
+ @element2.should_receive(:result_method).and_return(result2)
105
+
106
+ @resolver.api_method do |result|
107
+ result.result_method
108
+ end.should == [result1, result2]
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ describe ".vk_method_name" do
115
+ context "with a usual method name" do
116
+ context "without a namespace" do
117
+ it "returns 'methodName'" do
118
+ VkontakteApi::Resolver.vk_method_name(:api_method).first.should == 'apiMethod'
119
+ end
120
+ end
121
+
122
+ context "with a namespace" do
123
+ it "returns 'namespace.methodName'" do
124
+ VkontakteApi::Resolver.vk_method_name(:api_method, 'namespace').first.should == 'namespace.apiMethod'
125
+ end
126
+ end
127
+
128
+ it "returns :anything as a type" do
129
+ VkontakteApi::Resolver.vk_method_name(:api_method).last.should == :anything
130
+ end
131
+ end
132
+
133
+ context "with a predicate method name" do
134
+ it "returns method name without '?'" do
135
+ VkontakteApi::Resolver.vk_method_name(:is_it_working?).first.should == 'isItWorking'
136
+ end
137
+
138
+ it "returns :boolean as a type" do
139
+ VkontakteApi::Resolver.vk_method_name(:is_it_working?).last.should == :boolean
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "#typecast" do
145
+ before(:each) do
146
+ @resolver = VkontakteApi::Resolver.new
147
+ end
148
+
149
+ context "with an :anything type" do
150
+ it "returns it's argument untouched" do
151
+ @resolver.send(:typecast, :some_arg, :anything).should == :some_arg
152
+ end
153
+ end
154
+
155
+ context "with a :boolean type" do
156
+ context "and zero result" do
157
+ it "returns false" do
158
+ @resolver.send(:typecast, '0', :boolean).should == false
159
+ end
160
+ end
161
+
162
+ context "and non-zero parameter" do
163
+ it "returns true" do
164
+ @resolver.send(:typecast, '1', :boolean).should == true
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe VkontakteApi do
4
+ describe ".configure" do
5
+ VkontakteApi::Configuration::OPTION_NAMES.each do |name|
6
+ it "should set the #{name}" do
7
+ VkontakteApi.configure do |config|
8
+ config.send("#{name}=", name)
9
+ VkontakteApi.send(name).should == name
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ $: << File.expand_path('../lib', __FILE__)
3
+ require 'vkontakte_api/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'vkontakte_api'
7
+ s.version = VkontakteApi::VERSION
8
+ s.authors = ['Vsevolod Romashov']
9
+ s.email = ['7@7vn.ru']
10
+ s.homepage = ''
11
+ s.summary = %q{Ruby-way wrapper for VKontakte API}
12
+ s.description = %q{A transparent wrapper for API of vk.com social network called VKontakte. Supports ruby-way method naming (without any method lists inside), result typecasting and any faraday-supported http adapter of your choice (no hardcoded Net::HTTP).}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
17
+ s.require_paths = ['lib']
18
+
19
+ s.add_runtime_dependency 'activesupport', '~> 3.0'
20
+ s.add_runtime_dependency 'i18n', '~> 0.6'
21
+ s.add_runtime_dependency 'faraday', '~> 0.7.6'
22
+ s.add_runtime_dependency 'yajl-ruby', '~> 1.0'
23
+
24
+ s.add_development_dependency 'rake'
25
+ s.add_development_dependency 'rspec'
26
+ s.add_development_dependency 'pry'
27
+ s.add_development_dependency 'awesome_print'
28
+ end
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vkontakte_api
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vsevolod Romashov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: &70258037639260 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70258037639260
25
+ - !ruby/object:Gem::Dependency
26
+ name: i18n
27
+ requirement: &70258037638480 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '0.6'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70258037638480
36
+ - !ruby/object:Gem::Dependency
37
+ name: faraday
38
+ requirement: &70258037637640 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.7.6
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70258037637640
47
+ - !ruby/object:Gem::Dependency
48
+ name: yajl-ruby
49
+ requirement: &70258037636920 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70258037636920
58
+ - !ruby/object:Gem::Dependency
59
+ name: rake
60
+ requirement: &70258037656820 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70258037656820
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: &70258037656180 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70258037656180
80
+ - !ruby/object:Gem::Dependency
81
+ name: pry
82
+ requirement: &70258037655480 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70258037655480
91
+ - !ruby/object:Gem::Dependency
92
+ name: awesome_print
93
+ requirement: &70258037654980 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70258037654980
102
+ description: A transparent wrapper for API of vk.com social network called VKontakte.
103
+ Supports ruby-way method naming (without any method lists inside), result typecasting
104
+ and any faraday-supported http adapter of your choice (no hardcoded Net::HTTP).
105
+ email:
106
+ - 7@7vn.ru
107
+ executables: []
108
+ extensions: []
109
+ extra_rdoc_files: []
110
+ files:
111
+ - .gitignore
112
+ - Gemfile
113
+ - MIT-LICENSE
114
+ - README.md
115
+ - README.ru.md
116
+ - Rakefile
117
+ - lib/vkontakte_api.rb
118
+ - lib/vkontakte_api/api.rb
119
+ - lib/vkontakte_api/client.rb
120
+ - lib/vkontakte_api/configuration.rb
121
+ - lib/vkontakte_api/error.rb
122
+ - lib/vkontakte_api/namespaces.yml
123
+ - lib/vkontakte_api/resolver.rb
124
+ - lib/vkontakte_api/version.rb
125
+ - spec/spec_helper.rb
126
+ - spec/vkontakte_api/api_spec.rb
127
+ - spec/vkontakte_api/client_spec.rb
128
+ - spec/vkontakte_api/configuration_spec.rb
129
+ - spec/vkontakte_api/error_spec.rb
130
+ - spec/vkontakte_api/resolver_spec.rb
131
+ - spec/vkontakte_api_spec.rb
132
+ - vkontakte_api.gemspec
133
+ homepage: ''
134
+ licenses: []
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ! '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ segments:
146
+ - 0
147
+ hash: -2826215231838222847
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ none: false
150
+ requirements:
151
+ - - ! '>='
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ segments:
155
+ - 0
156
+ hash: -2826215231838222847
157
+ requirements: []
158
+ rubyforge_project:
159
+ rubygems_version: 1.8.10
160
+ signing_key:
161
+ specification_version: 3
162
+ summary: Ruby-way wrapper for VKontakte API
163
+ test_files:
164
+ - spec/spec_helper.rb
165
+ - spec/vkontakte_api/api_spec.rb
166
+ - spec/vkontakte_api/client_spec.rb
167
+ - spec/vkontakte_api/configuration_spec.rb
168
+ - spec/vkontakte_api/error_spec.rb
169
+ - spec/vkontakte_api/resolver_spec.rb
170
+ - spec/vkontakte_api_spec.rb