vkontakte_api 1.2 → 1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d37878c023a9ef41c525a2e80d94a1116bf7cdf4
4
- data.tar.gz: d6bee0ae8a1dfa7a74d74e26327f5cf880214e9b
3
+ metadata.gz: 60dffad7bbac6d779ff73eaeb39221648bd06b81
4
+ data.tar.gz: c702f943689840e842d49859f2bcc87b10fce869
5
5
  SHA512:
6
- metadata.gz: 100e3698409e4c1c76ac1adbbb75609675b92c965905e5218b32cc5f1dae49d0f69783db01bb7ca5729e724bae8e4718e0f3ffc7cb8ec8cc86a87a7e0d399301
7
- data.tar.gz: 43b9a423fd114d904b395f34fdf510eb72a48657722b2a88c2e15f82bdb8544b6aa2180fe8eb225a3e28aec20b12bbf3bc31cabb788f1f34739f62457d7ada19
6
+ metadata.gz: fc49252ddc7b95434e0f2f5ac59cb4ea4f749c1a30a7026b1bbefa5f570ae836f3b25125f70c9f8026aee2322b5cd4f878e19d90bc9a90f26948951f250d14b8
7
+ data.tar.gz: 90a2c6d2da5ac5e7e08851575373c7bc5e53684a88d5111e7a128026d3aa2accfb8b5c41bd2bedc373b3759009cf35d68c1132eb2f55691da93f37438fc9a1b0
data/.gitignore CHANGED
@@ -2,5 +2,6 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ tmp/*
5
6
  .yardoc/*
6
7
  spec/support/credentials.yml
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 1.3 (01.11.2013)
2
+
3
+ * Корректная работа API-методов `*.search` (спасибо [leonko](https://github.com/leonko))
4
+ * Поддержка IO-объектов в методе `upload` (спасибо [undr](https://github.com/undr))
5
+
1
6
  ## 1.2 (14.07.2013)
2
7
 
3
8
  * Повтор запроса при определенных ошибках
data/Guardfile CHANGED
@@ -1,7 +1,9 @@
1
- guard 'rspec' do
1
+ guard 'rspec', all_on_start: true, all_after_pass: true do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
3
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
4
  watch('spec/spec_helper.rb') { 'spec' }
5
+
6
+ watch('spec/support/mechanized_authorization.rb') { 'spec/integration_spec.rb' }
5
7
  end
6
8
 
7
9
  notification :terminal_notifier, activate: 'com.googlecode.iTerm2'
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ``` ruby
8
8
  # Gemfile
9
- gem 'vkontakte_api', '~> 1.2'
9
+ gem 'vkontakte_api', '~> 1.3'
10
10
  ```
11
11
 
12
12
  или просто
@@ -47,7 +47,7 @@ users.first.last_name # => "Дуров"
47
47
  # то блок будет выполнен для каждого элемента,
48
48
  # и метод вернет обработанный массив
49
49
  fields = [:first_name, :last_name, :screen_name]
50
- @vk.friends.get(fields: fields) do |friend|
50
+ @vk.friends.get(uid: 2, fields: fields) do |friend|
51
51
  "#{friend.first_name} '#{friend.screen_name}' #{friend.last_name}"
52
52
  end
53
53
  # => ["Павел 'durov' Дуров"]
@@ -64,6 +64,13 @@ url = 'http://cs303110.vkontakte.ru/upload.php?act=do_add'
64
64
  VkontakteApi.upload(url: url, photo: ['/path/to/file.jpg', 'image/jpeg'])
65
65
  ```
66
66
 
67
+ Если загружаемый файл доступен как открытый IO-объект, его можно передать альтернативным синтаксисом - IO-объект, MIME-тип и путь к файлу:
68
+
69
+ ``` ruby
70
+ url = 'http://cs303110.vkontakte.ru/upload.php?act=do_add'
71
+ VkontakteApi.upload(url: url, photo: [file_io, 'image/jpeg', '/path/to/file.jpg'])
72
+ ```
73
+
67
74
  Метод вернет ответ сервера ВКонтакте, преобразованный в `Hashie::Mash`; его можно использовать при вызове метода API на последнем этапе процесса загрузки.
68
75
 
69
76
  ### Авторизация
@@ -262,7 +269,6 @@ $ rails generate vkontakte_api:install
262
269
 
263
270
  ## Roadmap
264
271
 
265
- * настраиваемый retry запроса при стандартных исключениях
266
272
  * CLI-интерфейс с автоматической авторизацией
267
273
 
268
274
  ## Участие в разработке
@@ -69,6 +69,16 @@ module VkontakteApi
69
69
  end.keys
70
70
  end
71
71
 
72
+ # If the called method is a namespace, it creates and returns a new `VkontakteApi::Namespace` instance.
73
+ # Otherwise it creates a `VkontakteApi::Method` instance and calls it passing the arguments and a block.
74
+ def method_missing(*args, &block)
75
+ if Namespace.exists?(args.first)
76
+ create_namespace(args.first)
77
+ else
78
+ call_method(args, &block)
79
+ end
80
+ end
81
+
72
82
  private
73
83
  def settings
74
84
  @settings ||= self.get_user_settings
@@ -1,7 +1,36 @@
1
1
  module VkontakteApi
2
- # An API method namespace (such as `users` or `friends`). It just includes `Resolvable` and `Resolver`.
2
+ # An API method namespace (such as `users` or `friends`).
3
+ #
4
+ # It includes `Resolvable` and `Resolver` and calls API methods via `Resolver#call_method`.
5
+ # It also holds the list of all known namespaces.
3
6
  class Namespace
4
7
  include Resolvable
5
8
  include Resolver
9
+
10
+ # Creates and calls the `VkontakteApi::Method` using `VkontakteApi::Resolver#call_method`.
11
+ def method_missing(*args, &block)
12
+ call_method(args, &block)
13
+ end
14
+
15
+ class << self
16
+ # An array of all method namespaces.
17
+ #
18
+ # Lazily loads the list from `namespaces.yml` and caches it.
19
+ # @return [Array] An array of strings
20
+ def names
21
+ if @names.nil?
22
+ filename = File.expand_path('../namespaces.yml', __FILE__)
23
+ @names = YAML.load_file(filename)
24
+ end
25
+
26
+ @names
27
+ end
28
+
29
+ # Does a given namespace exist?
30
+ # @param [String, Symbol] name
31
+ def exists?(name)
32
+ names.include?(name.to_s)
33
+ end
34
+ end
6
35
  end
7
36
  end
@@ -7,7 +7,7 @@ module VkontakteApi
7
7
  # @param [String] name The name of this resolvable.
8
8
  # @option options [Hashie::Mash] :resolver A mash holding information about the previous resolver.
9
9
  def initialize(name, options = {})
10
- @name = name
10
+ @name = name.to_s
11
11
  @previous_resolver = options.delete(:resolver)
12
12
  end
13
13
 
@@ -1,41 +1,26 @@
1
1
  module VkontakteApi
2
2
  # A mixin for classes that will resolve other classes' objects via `#method_missing`.
3
3
  module Resolver
4
- # Main methods dispatch.
5
- #
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.
8
- def method_missing(method_name, *args, &block)
9
- method_name = method_name.to_s
10
-
11
- if Resolver.namespaces.include?(method_name)
12
- # called from Client
13
- Namespace.new(method_name, resolver: resolver)
14
- else
15
- # called from Namespace or one-level method
16
- Method.new(method_name, resolver: resolver).call(args.first || {}, &block)
17
- end
18
- end
19
-
20
4
  # A `Hashie::Mash` structure holding the name and token of current instance.
21
5
  # @return [Hashie::Mash]
22
6
  def resolver
23
7
  @resolver ||= Hashie::Mash.new(name: @name, token: token)
24
8
  end
25
9
 
10
+ private
11
+ def create_namespace(name)
12
+ Namespace.new(name, resolver: resolver)
13
+ end
14
+
15
+ def create_method(name)
16
+ Method.new(name, resolver: resolver)
17
+ end
18
+
19
+ def call_method(args, &block)
20
+ create_method(args.shift).call(args.first || {}, &block)
21
+ end
22
+
26
23
  class << self
27
- # An array of method namespaces.
28
- # Lazily loads the list from `namespaces.yml` and caches it.
29
- # @return [Array]
30
- def namespaces
31
- if @namespaces.nil?
32
- filename = File.expand_path('../namespaces.yml', __FILE__)
33
- @namespaces = YAML.load_file(filename)
34
- end
35
-
36
- @namespaces
37
- end
38
-
39
24
  # When this module is included, it undefines the `:send` instance method in the `base_class`
40
25
  # so it can be resolved via `method_missing`.
41
26
  def included(base_class)
@@ -12,15 +12,15 @@ module VkontakteApi
12
12
  # VkontakteApi.upload(
13
13
  # url: 'http://example.com/upload',
14
14
  # file1: ['/path/to/file1.jpg', 'image/jpeg'],
15
- # file2: ['/path/to/file2.png', 'image/png']
15
+ # file2: [io_object, 'image/png', '/path/to/file2.png']
16
16
  # )
17
17
  def upload(params = {})
18
18
  url = params.delete(:url)
19
19
  raise ArgumentError, 'You should pass :url parameter' unless url
20
20
 
21
21
  files = {}
22
- params.each do |param_name, (file_path, file_type)|
23
- files[param_name] = Faraday::UploadIO.new(file_path, file_type)
22
+ params.each do |param_name, (file_path_or_io, file_type, file_path)|
23
+ files[param_name] = Faraday::UploadIO.new(file_path_or_io, file_type, file_path)
24
24
  end
25
25
 
26
26
  API.connection.post(url, files).body
@@ -1,4 +1,4 @@
1
1
  module VkontakteApi
2
2
  # Library version.
3
- VERSION = '1.2'
3
+ VERSION = '1.3'
4
4
  end
@@ -13,70 +13,67 @@ describe "Integration" do
13
13
  end
14
14
 
15
15
  describe "unauthorized requests" do
16
- before(:each) do
17
- @vk = VK::Client.new
18
- end
16
+ let(:vk) { VK::Client.new }
19
17
 
20
18
  it "get users" do
21
- user = @vk.users.get(uid: 1).first
22
- user.uid.should == 1
23
- user.last_name.should_not be_empty
24
- user.first_name.should_not be_empty
19
+ user = vk.users.get(uid: 1).first
20
+ expect(user.uid).to eq(1)
21
+ expect(user.last_name).not_to be_empty
22
+ expect(user.first_name).not_to be_empty
23
+ end
24
+
25
+ it "search newsfeed" do
26
+ news = vk.newsfeed.search(q: 'vk', count: 1)
27
+ expect(news).to be_a(Enumerable)
25
28
  end
26
29
  end
27
30
 
28
31
  if MechanizedAuthorization.on?
29
32
  describe "authorized requests" do
30
- before(:each) do
31
- @vk = MechanizedAuthorization.client
32
- end
33
+ let(:vk) { MechanizedAuthorization.client }
33
34
 
34
35
  it "get groups" do
35
- groups = @vk.groups.get
36
- groups.should include(1)
36
+ pending 'MechanizedAuthorization not working'
37
+ expect(vk.groups.get).to include(1)
37
38
  end
38
39
  end
39
40
 
40
41
  describe "requests with camelCase and predicate methods" do
41
- before(:each) do
42
- @vk = MechanizedAuthorization.client
43
- end
42
+ let(:vk) { MechanizedAuthorization.client }
44
43
 
45
44
  it "convert method names to vk.com format" do
46
- @vk.is_app_user?.should be_true
45
+ pending 'MechanizedAuthorization not working'
46
+ expect(vk.is_app_user?).to be_true
47
47
  end
48
48
  end
49
49
  end
50
50
 
51
51
  describe "requests with array arguments" do
52
- before(:each) do
53
- @vk = VK::Client.new
54
- end
52
+ let(:vk) { VK::Client.new }
55
53
 
56
54
  it "join arrays with a comma" do
57
- users = @vk.users.get(uids: [1, 2, 3], fields: %w[first_name last_name screen_name])
58
- users.first.screen_name.should_not be_empty
55
+ users = vk.users.get(uids: [1, 2, 3], fields: %w[first_name last_name screen_name])
56
+ expect(users.first.screen_name).not_to be_empty
59
57
  end
60
58
  end
61
59
 
62
60
  describe "requests with blocks" do
63
- before(:each) do
64
- @vk = VK::Client.new
65
- end
61
+ let(:vk) { VK::Client.new }
66
62
 
67
63
  it "map the result with a block" do
68
- users = @vk.users.get(uid: 1) do |user|
64
+ users = vk.users.get(uid: 1) do |user|
69
65
  "#{user.last_name} #{user.first_name}"
70
66
  end
71
67
 
72
- users.first.should_not be_empty
68
+ expect(users.first).not_to be_empty
73
69
  end
74
70
  end
75
71
 
76
72
  describe "authorization" do
77
73
  context "with a scope" do
78
74
  it "returns a correct url" do
79
- VK.authorization_url(scope: %w[friends groups]).should include('scope=friends%2Cgroups')
75
+ url = VK.authorization_url(scope: %w[friends groups])
76
+ expect(url).to include('scope=friends%2Cgroups')
80
77
  end
81
78
  end
82
79
  end
@@ -23,13 +23,13 @@ describe VkontakteApi::API do
23
23
 
24
24
  context "called with a token parameter" do
25
25
  it "sends it to .connection" do
26
- subject.should_receive(:connection).with(url: VkontakteApi::API::URL_PREFIX, token: 'token')
26
+ expect(subject).to receive(:connection).with(url: VkontakteApi::API::URL_PREFIX, token: 'token')
27
27
  subject.call('apiMethod', { some: :params }, 'token')
28
28
  end
29
29
  end
30
30
 
31
31
  it "returns the response body" do
32
- subject.call('apiMethod').should == @result
32
+ expect(subject.call('apiMethod')).to eq(@result)
33
33
  end
34
34
 
35
35
  it "uses an HTTP verb from VkontakteApi.http_verb" do
@@ -37,7 +37,7 @@ describe VkontakteApi::API do
37
37
  VkontakteApi.http_verb = http_verb
38
38
 
39
39
  response = double("Response", body: double)
40
- @connection.should_receive(:send).with(http_verb, 'apiMethod', {}).and_return(response)
40
+ expect(@connection).to receive(:send).with(http_verb, 'apiMethod', {}).and_return(response)
41
41
  subject.call('apiMethod')
42
42
  end
43
43
 
@@ -51,27 +51,27 @@ describe VkontakteApi::API do
51
51
  faraday_options = double("Faraday options")
52
52
  VkontakteApi.stub(:faraday_options).and_return(faraday_options)
53
53
  url = double("URL")
54
- Faraday.should_receive(:new).with(url, faraday_options)
55
- connection = subject.connection(url: url)
54
+
55
+ expect(Faraday).to receive(:new).with(url, faraday_options)
56
+ subject.connection(url: url)
56
57
  end
57
58
 
58
59
  context "without a token" do
59
60
  it "creates a connection without an oauth2 middleware" do
60
- connection = subject.connection
61
- connection.builder.handlers.map(&:name).should_not include('FaradayMiddleware::OAuth2')
61
+ handler_names = subject.connection.builder.handlers.map(&:name)
62
+ expect(handler_names).not_to include('FaradayMiddleware::OAuth2')
62
63
  end
63
64
  end
64
65
 
65
66
  context "with a token" do
66
- before(:each) do
67
- @token = double("Token")
68
- end
67
+ let(:token) { double("Token") }
69
68
 
70
69
  it "creates a connection with an oauth2 middleware" do
71
- connection = subject.connection(token: @token)
70
+ connection = subject.connection(token: token)
72
71
  handler = connection.builder.handlers.first
73
- handler.name.should == 'FaradayMiddleware::OAuth2'
74
- handler.instance_variable_get(:@args).should == [@token]
72
+
73
+ expect(handler.name).to eq('FaradayMiddleware::OAuth2')
74
+ expect(handler.instance_variable_get(:@args)).to eq([token])
75
75
  end
76
76
  end
77
77
  end
@@ -18,35 +18,38 @@ describe VkontakteApi::Authorization do
18
18
 
19
19
  @client = double("OAuth2::Client instance", auth_code: @auth_code, implicit: @implicit, client_credentials: @client_credentials)
20
20
  OAuth2::Client.stub(:new).and_return(@client)
21
-
22
- @auth = Object.new
23
- @auth.extend VkontakteApi::Authorization
24
21
  end
25
22
 
23
+ let(:auth) do
24
+ Object.new.tap do |object|
25
+ object.extend VkontakteApi::Authorization
26
+ end
27
+ end
28
+
26
29
  describe "#authorization_url" do
27
30
  before(:each) do
28
- @auth.stub(:client).and_return(@client)
31
+ auth.stub(:client).and_return(@client)
29
32
  end
30
33
 
31
34
  context "with a site type" do
32
35
  it "returns a valid authorization url" do
33
- @auth_code.should_receive(:authorize_url).with(redirect_uri: @redirect_uri)
34
- @auth.authorization_url(type: :site).should == @url
36
+ expect(@auth_code).to receive(:authorize_url).with(redirect_uri: @redirect_uri)
37
+ expect(auth.authorization_url(type: :site)).to eq(@url)
35
38
  end
36
39
  end
37
40
 
38
41
  context "with a client type" do
39
42
  it "returns a valid authorization url" do
40
- @implicit.should_receive(:authorize_url).with(redirect_uri: @redirect_uri)
41
- @auth.authorization_url(type: :client).should == @url
43
+ expect(@implicit).to receive(:authorize_url).with(redirect_uri: @redirect_uri)
44
+ expect(auth.authorization_url(type: :client)).to eq(@url)
42
45
  end
43
46
  end
44
47
 
45
48
  context "given a redirect_uri" do
46
49
  it "prefers the given uri over VkontakteApi.redirect_uri" do
47
50
  redirect_uri = 'http://example.com/oauth/callback'
48
- @auth_code.should_receive(:authorize_url).with(redirect_uri: redirect_uri)
49
- @auth.authorization_url(redirect_uri: redirect_uri)
51
+ expect(@auth_code).to receive(:authorize_url).with(redirect_uri: redirect_uri)
52
+ auth.authorization_url(redirect_uri: redirect_uri)
50
53
  end
51
54
  end
52
55
 
@@ -55,9 +58,9 @@ describe VkontakteApi::Authorization do
55
58
  scope = double("Scope")
56
59
  flat_scope = double("Flat scope")
57
60
 
58
- VkontakteApi::Utils.should_receive(:flatten_argument).with(scope).and_return(flat_scope)
59
- @auth_code.should_receive(:authorize_url).with(redirect_uri: @redirect_uri, scope: flat_scope)
60
- @auth.authorization_url(scope: scope)
61
+ expect(VkontakteApi::Utils).to receive(:flatten_argument).with(scope).and_return(flat_scope)
62
+ expect(@auth_code).to receive(:authorize_url).with(redirect_uri: @redirect_uri, scope: flat_scope)
63
+ auth.authorization_url(scope: scope)
61
64
  end
62
65
  end
63
66
  end
@@ -70,42 +73,42 @@ describe VkontakteApi::Authorization do
70
73
  end
71
74
 
72
75
  it "gets the token" do
73
- @auth_code.should_receive(:get_token).with(@code, redirect_uri: @redirect_uri)
74
- @auth.authorize(type: :site, code: @code)
76
+ expect(@auth_code).to receive(:get_token).with(@code, redirect_uri: @redirect_uri)
77
+ auth.authorize(type: :site, code: @code)
75
78
  end
76
79
  end
77
80
 
78
81
  context "with an app_server type" do
79
82
  it "gets the token" do
80
- @client_credentials.should_receive(:get_token).with({ redirect_uri: @redirect_uri }, subject::OPTIONS[:client_credentials])
81
- @auth.authorize(type: :app_server)
83
+ expect(@client_credentials).to receive(:get_token).with({ redirect_uri: @redirect_uri }, subject::OPTIONS[:client_credentials])
84
+ auth.authorize(type: :app_server)
82
85
  end
83
86
  end
84
87
 
85
88
  context "with an unknown type" do
86
89
  it "raises an ArgumentError" do
87
90
  expect {
88
- @auth.authorize(type: :unknown)
91
+ auth.authorize(type: :unknown)
89
92
  }.to raise_error(ArgumentError)
90
93
  end
91
94
  end
92
95
 
93
96
  it "builds a VkontakteApi::Client instance with the received token" do
94
97
  client = double("VkontakteApi::Client instance")
95
- VkontakteApi::Client.should_receive(:new).with(@token).and_return(client)
96
- @auth.authorize.should == client
98
+ expect(VkontakteApi::Client).to receive(:new).with(@token).and_return(client)
99
+ expect(auth.authorize).to eq(client)
97
100
  end
98
101
  end
99
102
 
100
103
  describe "#client" do
101
104
  it "creates and returns an OAuth2::Client instance" do
102
- OAuth2::Client.should_receive(:new).with(@app_id, @app_secret, subject::OPTIONS[:client])
103
- @auth.send(:client).should == @client
105
+ expect(OAuth2::Client).to receive(:new).with(@app_id, @app_secret, subject::OPTIONS[:client])
106
+ expect(auth.send(:client)).to eq(@client)
104
107
  end
105
108
 
106
109
  it "caches the result" do
107
- OAuth2::Client.should_receive(:new).once
108
- 5.times { @auth.send(:client) }
110
+ expect(OAuth2::Client).to receive(:new).once
111
+ 5.times { auth.send(:client) }
109
112
  end
110
113
  end
111
114
  end