disqus_api 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 133d31109b75e6a7a8a3948ae883667b419c9d41
4
- data.tar.gz: 2316f34bd676de9379991a8f5f260db9fe17307b
3
+ metadata.gz: 86c8f27e2bb06b2355b45fc73a69d07b830d0372
4
+ data.tar.gz: df17c1bb6520a90fed6963c6cf873c9bddc5ce11
5
5
  SHA512:
6
- metadata.gz: b7c188e126d73f1f8b4a4b2f7b07fbd872ce6552d0f26b55d5ae2349b86906c54bbb7dfd06b3737380a7b695e862a8f7dd416b6dcba7db499312ff3dabc57ab0
7
- data.tar.gz: 4b45529a2925f8cfd95e82b8e760c5d03ec4036995af60d06aaf999eb6613fe2825077e40301a6b7861fb9de31972d2de7c02194fd9bd1dabf2e301bea83dcd7
6
+ metadata.gz: 23ade579f2fcb9b142bcb539d85278b4d6aebaf726bc3030fbb5e9d58614bffbaa10660c446b30612ad02cce225df498f51f45cec6427b383f5719a62075a8fe
7
+ data.tar.gz: eb1169533ebe20d233c132177f418ccc3dee21742af4a698848dc20e8e839f319dd6a1cef14d7b429682cb52e53e27abe07d83e7806cf4cf90cacff8b8c236a7
@@ -0,0 +1,5 @@
1
+ guard :rspec do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/README.md CHANGED
@@ -1,9 +1,11 @@
1
1
  # Disqus API for Ruby
2
2
  [![Gem Version](https://badge.fury.io/rb/disqus_api.png)](http://badge.fury.io/rb/disqus_api)
3
- [![Build Status](https://travis-ci.org/einzige/disqus_api.png?branch=master)](https://travis-ci.org/einzige/disqus_api)
3
+ [![Build Status](https://travis-ci.org/toptal/disqus_api.png?branch=master)](https://travis-ci.org/toptal/disqus_api)
4
4
 
5
5
  Provides clean Disqus REST API for your Ruby app. Currently supported API version: 3.0.
6
6
 
7
+ See also [Disqus API for Rails](https://github.com/toptal/disqus_api_rails).
8
+
7
9
  ## Install
8
10
 
9
11
  ```bash
@@ -13,6 +15,8 @@ gem install disqus_api
13
15
  ## Configure
14
16
 
15
17
  ```ruby
18
+ require 'disqus_api'
19
+
16
20
  DisqusApi.config = {api_secret: 'secret key',
17
21
  api_key: 'public key',
18
22
  access_token: 'token from app settings'}
@@ -68,14 +72,48 @@ DisqusApi.v3.posts.list(forum: 'my_form').all
68
72
 
69
73
  ### Pagination
70
74
 
75
+ Step by step:
76
+
71
77
  ```ruby
72
78
  first_page = DisqusApi.v3.posts.list(forum: 'my_forum', limit: 10)
73
79
 
74
80
  second_page = first_page.next
75
81
  third_page = second_page.next
82
+ first_page = thrid_page.prev.prev
76
83
  # ...
77
84
  ```
78
85
 
86
+ It is useful to go through all records. This way you will pass every page in batches by 10:
87
+
88
+ ```ruby
89
+ DisqusApi.v3.posts.list(limit: 10).each_resource do |comment|
90
+ puts comment.inspect
91
+ end
92
+ ```
93
+
94
+ You can also iterate collection page by page.
95
+
96
+ ```ruby
97
+ DisqusApi.v3.posts.each_page do |comments|
98
+ comments.each do |comment|
99
+ puts comment.inspect
100
+ end
101
+ end
102
+ ```
103
+
104
+ You can also move on next page:
105
+
106
+ ```ruby
107
+ response = DisqusApi.v3.posts
108
+ response.next!
109
+ ```
110
+
111
+ Or on previous one:
112
+
113
+ ```ruby
114
+ response.prev!
115
+ ```
116
+
79
117
  ### Performing custom requests
80
118
 
81
119
  ```ruby
@@ -83,18 +121,29 @@ DisqusApi.v3.get('posts/list.json', forum: 'my_forum')
83
121
  DisqusApi.v3.post('posts/create.json', forum: 'my_forum')
84
122
  ```
85
123
 
86
- ### Using in test environment
124
+ ### Handling exceptions
87
125
 
88
- Disqus API uses Faraday gem, refer to its documentation for details.
126
+ Just catch `DisqusApi::InvalidApiRequestError`. It has `code` to identify problems with a request.
127
+
128
+ ```ruby
129
+ begin
130
+ DisqusApi.v3.posts.list(forum: 'something-wrong')
131
+ rescue DisqusApi::InvalidApiRequestError => e
132
+ e.response.inspect
133
+ end
134
+
135
+ #=> {"code"=>2, "response"=>"Invalid argument, 'forum': Unable to find forum 'something-wrong'"}
136
+ ```
137
+
138
+ ### Using in test environment
89
139
 
90
140
  ```ruby
91
141
  before :all do
92
142
  # You can move this block in RSpec initializer or `spec_helper.rb`
93
143
 
94
- stubbed_request = Faraday::Adapter::Test::Stubs.new do |stub|
144
+ DisqusApi.stub_requests do |stub|
95
145
  stub.get('/api/3.0/users/details.json') { [200, {}, {code: 0, body: {response: :whatever}}.to_json] }
96
146
  end
97
- DisqusApi.adapter = [:test, stubbed_requests]
98
147
  end
99
148
 
100
149
  it 'performs requests' do
@@ -102,6 +151,28 @@ it 'performs requests' do
102
151
  end
103
152
  ```
104
153
 
154
+ Disqus API uses Faraday gem, refer to its documentation for details.
155
+
156
+ ### Running specs
157
+
158
+ Use any of the following commands from the project directory:
159
+
160
+ ```bash
161
+ rspec
162
+ ```
163
+
164
+ ```ruby
165
+ rake # rake gem must be installed
166
+ ```
167
+
168
+ In order to test on a real Discus account
169
+ - specify `spec/config/disqus.yml` (see `spec/config/disqus.yml.example` for details)
170
+ - run specs passing `USE_DISQUS_ACCOUNT` environment variable:
171
+
172
+ ```bash
173
+ USE_DISQUS_ACCOUNT=1 rspec
174
+ ```
175
+
105
176
  ## Contributing to disqus_api
106
177
 
107
178
  - Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
@@ -2,12 +2,12 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{disqus_api}
5
- s.version = "0.0.2"
5
+ s.version = "0.0.3"
6
6
 
7
7
  s.date = %q{2013-12-09}
8
- s.authors = ["Sergei Zinin"]
8
+ s.authors = ["Sergei Zinin (einzige)"]
9
9
  s.email = %q{szinin@gmail.com}
10
- s.homepage = %q{http://github.com/einzige/disqus_api}
10
+ s.homepage = %q{http://github.com/toptal/disqus_api}
11
11
 
12
12
  s.licenses = ["MIT"]
13
13
 
@@ -21,6 +21,6 @@ Gem::Specification.new do |s|
21
21
  s.add_runtime_dependency 'activesupport', ">= 3.0.0"
22
22
  s.add_runtime_dependency 'faraday', ">= 0.8"
23
23
  s.add_runtime_dependency 'faraday_middleware', ">= 0.9"
24
- s.add_development_dependency 'bundler'
24
+ s.add_development_dependency 'rspec'
25
25
  end
26
26
 
@@ -1,4 +1,5 @@
1
1
  require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'active_support/core_ext/hash/slice'
2
3
  require 'active_support/core_ext/object/try'
3
4
  require 'yaml'
4
5
  require 'json'
@@ -9,8 +10,10 @@ require 'disqus_api/api'
9
10
  require 'disqus_api/namespace'
10
11
  require 'disqus_api/request'
11
12
  require 'disqus_api/response'
13
+ require 'disqus_api/invalid_api_request_error'
12
14
 
13
15
  module DisqusApi
16
+ VERSION = '0.0.3'
14
17
 
15
18
  def self.adapter
16
19
  @adapter || Faraday.default_adapter
@@ -22,7 +25,7 @@ module DisqusApi
22
25
 
23
26
  # @return [ActiveSupport::HashWithIndifferentAccess]
24
27
  def self.config
25
- @config || raise("No configuration specified for Disqus")
28
+ @config || {}
26
29
  end
27
30
 
28
31
  # @param [Hash] config
@@ -39,6 +42,11 @@ module DisqusApi
39
42
  Api.new(version, YAML.load_file(File.join(File.dirname(__FILE__), "apis/#{version}.yml")))
40
43
  end
41
44
 
45
+ def self.stub_requests(&block)
46
+ stubbed_requests = Faraday::Adapter::Test::Stubs.new(&block)
47
+ DisqusApi.adapter = [:test, stubbed_requests]
48
+ end
49
+
42
50
  # @return [Api]
43
51
  def self.v3
44
52
  @v3 ||= init('3.0')
@@ -1,10 +1,4 @@
1
1
  module DisqusApi
2
- class InvalidApiRequestError < Exception
3
- def initialize(response, message = response.inspect)
4
- super(response)
5
- end
6
- end
7
-
8
2
  class Api
9
3
  DEFAULT_VERSION = '3.0'
10
4
  attr_reader :version, :endpoint, :specifications, :namespaces
@@ -38,7 +32,7 @@ module DisqusApi
38
32
  builder.use Faraday::Request::UrlEncoded
39
33
  builder.use Faraday::Response::ParseJson
40
34
 
41
- builder.params.merge!(DisqusApi.config)
35
+ builder.params.merge!(DisqusApi.config.slice(:api_secret, :api_key, :access_token))
42
36
 
43
37
  builder.adapter(*DisqusApi.adapter)
44
38
  end
@@ -0,0 +1,13 @@
1
+ module DisqusApi
2
+ class InvalidApiRequestError < StandardError
3
+ attr_reader :response
4
+
5
+ # @param [Hash] response
6
+ # @param [Stirng] message
7
+ def initialize(response, message = response.inspect)
8
+ @response = response
9
+ super(message)
10
+ end
11
+ end
12
+ end
13
+
@@ -2,7 +2,7 @@ module DisqusApi
2
2
  class Request
3
3
  attr_reader :api, :path, :namespace, :action, :arguments, :type
4
4
 
5
- # @param [Class<DisqusApi::Api>] api
5
+ # @param [DisqusApi::Api] api
6
6
  # @param [String] namespace
7
7
  # @param [String] action
8
8
  # @param [Hash] arguments Request parameters
@@ -12,17 +12,43 @@ module DisqusApi
12
12
  super(@content)
13
13
  end
14
14
 
15
- # Fetches all records going through pagination
15
+ # Fetches all response collection entries going through pagination
16
16
  # @return [Array<Hash>]
17
17
  def all
18
- [].tap do |result|
18
+ each_resource.to_a
19
+ end
20
+
21
+ # Iterates through each response entry through all pages
22
+ # @return [Enumerator<Hash>]
23
+ def each_resource(&block)
24
+ Enumerator.new do |result|
25
+ each_page { |resources| resources.each { |resource| result << resource } }
26
+ end.each(&block)
27
+ end
28
+
29
+ # Iterates through every single page
30
+ # @return [Enumerator<Array<Hash>>]
31
+ def each_page(&block)
32
+ Enumerator.new do |result|
19
33
  next_response = self
20
34
 
21
35
  while next_response
22
- result.concat(next_response.body)
36
+ result << next_response.body.to_a
23
37
  next_response = next_response.next
24
38
  end
25
- end
39
+ end.each(&block)
40
+ end
41
+
42
+ # @return [Response]
43
+ def next!
44
+ self.merge!(self.next) if has_next?
45
+ self
46
+ end
47
+
48
+ # @return [Response]
49
+ def prev!
50
+ self.merge!(self.prev) if has_prev?
51
+ self
26
52
  end
27
53
 
28
54
  # @return [Response, nil]
@@ -32,15 +58,31 @@ module DisqusApi
32
58
  end
33
59
  end
34
60
 
61
+ # @return [Response, nil]
62
+ def prev
63
+ if has_prev?
64
+ request.response(arguments.merge(cursor: prev_cursor))
65
+ end
66
+ end
67
+
35
68
  def has_next?
36
69
  self['cursor']['hasNext']
37
70
  end
38
71
 
72
+ def has_prev?
73
+ self['cursor']['hasPrev']
74
+ end
75
+
39
76
  # @return [String]
40
77
  def next_cursor
41
78
  self['cursor']['next']
42
79
  end
43
80
 
81
+ # @return [String]
82
+ def prev_cursor
83
+ self['cursor']['prev']
84
+ end
85
+
44
86
  # @return [Hash]
45
87
  def body
46
88
  self['response']
@@ -29,11 +29,28 @@ describe DisqusApi::Response do
29
29
  end
30
30
  end
31
31
 
32
+ describe "#has_prev?" do
33
+ context "has" do
34
+ let(:response_body) { {'cursor' => {'hasPrev' => true}} }
35
+ its(:has_prev?) { should be_true }
36
+ end
37
+
38
+ context 'has not' do
39
+ let(:response_body) { {'cursor' => {'hasPrev' => false}} }
40
+ its(:has_prev?) { should be_false }
41
+ end
42
+ end
43
+
32
44
  describe "#next_cursor" do
33
45
  let(:response_body) { {'cursor' => {'next' => 'next identifier'}} }
34
46
  its(:next_cursor) { should == 'next identifier' }
35
47
  end
36
48
 
49
+ describe "#prev_cursor" do
50
+ let(:response_body) { {'cursor' => {'prev' => 'prev identifier'}} }
51
+ its(:prev_cursor) { should == 'prev identifier' }
52
+ end
53
+
37
54
  describe "#body" do
38
55
  let(:response_body) { {'response' => {'received' => true}} }
39
56
  its(:body) { should == {'received' => true} }
@@ -46,37 +63,144 @@ describe DisqusApi::Response do
46
63
 
47
64
  describe "#next" do
48
65
  context "has next page" do
49
- let(:response_body) { {'cursor' => {'hasNext' => true, 'next' => 'Next:2'}} }
66
+ let(:response_body) { {'cursor' => {'hasNext' => true, 'next' => 'another_page'}} }
50
67
  let(:next_page_response) { double('next_page_response') }
51
68
 
52
69
  before do
53
- request.should_receive(:response).with({limit: 1, cursor: 'Next:2'}).and_return(next_page_response)
70
+ request.should_receive(:response).with({limit: 1, cursor: 'another_page'}).and_return(next_page_response)
54
71
  end
55
72
 
56
73
  its(:next) { should == next_page_response }
57
74
  end
58
75
 
59
76
  context 'has no next page' do
60
- let(:response_body) { {'cursor' => {'hasNext' => false, 'next' => 'Next:2'}} }
77
+ let(:response_body) { {'cursor' => {'hasNext' => false, 'next' => 'another_page'}} }
61
78
  its(:next) { should be_nil }
62
79
  end
63
80
  end
64
81
 
65
- describe "#all" do
66
- let(:response_body) { {'cursor' => {'hasNext' => false, 'next' => 'Next:2'}, 'response' => ['page_1_elem_1']} }
67
- its(:all) { should == ['page_1_elem_1'] }
82
+ describe "#next" do
83
+ context "has previous page" do
84
+ let(:response_body) { {'cursor' => {'hasPrev' => true, 'prev' => 'another_page'}} }
85
+ let(:prev_page_response) { double('prev_page_response') }
68
86
 
69
- context "many pages" do
70
- let(:response_body) { {'cursor' => {'hasNext' => true, 'next' => 'Next:2'}, 'response' => ['page_1_elem_1']} }
71
- let(:next_page_response) { double('next_page_response') }
87
+ before do
88
+ request.should_receive(:response).with({limit: 1, cursor: 'another_page'}).and_return(prev_page_response)
89
+ end
90
+
91
+ its(:prev) { should == prev_page_response }
92
+ end
93
+
94
+ context 'has no prev page' do
95
+ let(:response_body) { {'cursor' => {'hasPrev' => false, 'prev' => 'another_page'}} }
96
+ its(:prev) { should be_nil }
97
+ end
98
+ end
72
99
 
100
+ describe "pagination" do
101
+ its(:each_page) { should be_a(Enumerator) }
102
+
103
+ context "building a enumerator" do
73
104
  before do
74
- request.should_receive(:response).with({limit: 1, cursor: 'Next:2'}).and_return(next_page_response)
75
- next_page_response.should_receive(:body).and_return(['page_2_elem_1'])
76
- next_page_response.should_receive(:next).and_return(nil)
105
+ request.should_not_receive(:next)
106
+ request.should_not_receive(:perform)
107
+ end
108
+
109
+ describe "#each_page" do
110
+ it 'acts as iterator' do
111
+ subject.each_page
112
+ end
77
113
  end
78
114
 
79
- its(:all) { should == ['page_1_elem_1', 'page_2_elem_1'] }
115
+ describe "#each_resource" do
116
+ it 'acts as iterator' do
117
+ subject.each_resource
118
+ end
119
+ end
120
+ end
121
+
122
+ context "multiple pages" do
123
+ before do
124
+ request.should_receive(:perform).with(arguments.merge(cursor: 'another_page')).and_return(another_page_response_body)
125
+ end
126
+
127
+ let(:page_1_elem_1) { double('page_1_elem_1') }
128
+ let(:page_2_elem_1) { double('page_2_elem_1') }
129
+
130
+ let(:response_body) {
131
+ {'cursor' => {'hasNext' => true, 'next' => 'another_page'}, 'page' => 1, 'response' => [page_1_elem_1]}
132
+ }
133
+ let(:another_page_response_body) {
134
+ {'cursor' => {'hasNext' => false}, 'page' => 2, 'response' => [page_2_elem_1]}
135
+ }
136
+ its(:all) { should == [page_1_elem_1, page_2_elem_1] }
137
+
138
+ describe "#next!" do
139
+ before { response.next! }
140
+ it { should be_a(described_class) }
141
+
142
+ it 'steps on next page' do
143
+ response['page'].should == 2
144
+ end
145
+
146
+ context "no next" do
147
+ before { response.next! }
148
+
149
+ it 'does nothing' do
150
+ response['page'].should == 2
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "#prev!" do
156
+ let(:response_body) {
157
+ {'cursor' => {'hasPrev' => true, 'prev' => 'another_page'}, 'page' => 2}
158
+ }
159
+ let(:another_page_response_body) {
160
+ {'cursor' => {'hasPrev' => false}, 'page' => 1}
161
+ }
162
+
163
+ before { response.prev! }
164
+ it { should be_a(described_class) }
165
+
166
+ it 'steps on previous page' do
167
+ response['page'].should == 1
168
+ end
169
+
170
+ context "no previous" do
171
+ before { response.prev! }
172
+
173
+ it 'does nothing' do
174
+ response['page'].should == 1
175
+ end
176
+ end
177
+ end
178
+
179
+ describe "#each_page" do
180
+ it 'returns each page' do
181
+ subject.each_page.to_a.should == [[page_1_elem_1], [page_2_elem_1]]
182
+ end
183
+
184
+ it 'iterates through each page' do
185
+ page_1_elem_1.should_receive(:get_block_message)
186
+ page_2_elem_1.should_receive(:get_block_message)
187
+
188
+ subject.each_page { |page| page.each(&:get_block_message) }
189
+ end
190
+ end
191
+
192
+ describe "#each_resource" do
193
+ it 'returns each record iterator' do
194
+ subject.each_resource.to_a.should == [page_1_elem_1, page_2_elem_1]
195
+ end
196
+
197
+ it 'iterates through each resource' do
198
+ page_1_elem_1.should_receive(:get_block_message)
199
+ page_2_elem_1.should_receive(:get_block_message)
200
+
201
+ subject.each_resource(&:get_block_message)
202
+ end
203
+ end
80
204
  end
81
205
  end
82
206
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: disqus_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
- - Sergei Zinin
7
+ - Sergei Zinin (einzige)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0.9'
55
55
  - !ruby/object:Gem::Dependency
56
- name: bundler
56
+ name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - '>='
@@ -76,12 +76,14 @@ files:
76
76
  - .gitignore
77
77
  - .travis.yml
78
78
  - Gemfile
79
+ - Guardfile
79
80
  - README.md
80
81
  - Rakefile
81
82
  - disqus_api.gemspec
82
83
  - lib/apis/3.0.yml
83
84
  - lib/disqus_api.rb
84
85
  - lib/disqus_api/api.rb
86
+ - lib/disqus_api/invalid_api_request_error.rb
85
87
  - lib/disqus_api/namespace.rb
86
88
  - lib/disqus_api/request.rb
87
89
  - lib/disqus_api/response.rb
@@ -92,7 +94,7 @@ files:
92
94
  - spec/disqus_api/response_spec.rb
93
95
  - spec/disqus_api_spec.rb
94
96
  - spec/spec_helper.rb
95
- homepage: http://github.com/einzige/disqus_api
97
+ homepage: http://github.com/toptal/disqus_api
96
98
  licenses:
97
99
  - MIT
98
100
  metadata: {}