vkontakte_api 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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