disqus_api 0.0.2 → 0.0.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: 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: {}