github_api 0.3.9 → 0.4.0

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,34 @@
1
+ module Github
2
+ module PagedRequest
3
+ include Github::Constants
4
+
5
+ extend self
6
+
7
+ FIRST_PAGE = 1
8
+
9
+ PER_PAGE = 25
10
+
11
+ class << self
12
+ attr_accessor :page, :per_page
13
+ end
14
+
15
+ def default_page_size
16
+ Github.api_client.per_page ? Github.api_client.per_page : PER_PAGE
17
+ end
18
+
19
+ def default_page
20
+ Github.api_client.page ? Github.api_client.page : FIRST_PAGE
21
+ end
22
+
23
+ def page_request(path, params={})
24
+ params[PARAM_PER_PAGE] = default_page_size unless params[PARAM_PER_PAGE]
25
+ params[PARAM_PAGE] = default_page unless params[PARAM_PAGE]
26
+
27
+ Github::PagedRequest.page = params[PARAM_PAGE]
28
+ Github::PagedRequest.per_page = params[PARAM_PER_PAGE]
29
+
30
+ Github.api_client.get path, params
31
+ end
32
+
33
+ end # PagedRequest
34
+ end # Github
@@ -225,11 +225,11 @@ module Github
225
225
  def repos(*args)
226
226
  params = args.last.is_a?(Hash) ? args.pop : {}
227
227
  _normalize_params_keys(params)
228
- # _merge_user_into_params!(params) unless params.has_key?('user')
228
+ _merge_user_into_params!(params) unless params.has_key?('user')
229
229
  _filter_params_keys(%w[ org user type ], params)
230
230
 
231
231
  response = if (user_name = params.delete("user"))
232
- get("/users/#{user_name}/repos")
232
+ get("/users/#{user_name}/repos", params)
233
233
  elsif (org_name = params.delete("org"))
234
234
  get("/orgs/#{org_name}/repos", params)
235
235
  else
@@ -6,7 +6,14 @@ module Github
6
6
  class Response::Helpers < Response
7
7
 
8
8
  def on_complete(env)
9
- env[:body].extend(Github::Result)
9
+ env[:body].class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
10
+ include Github::Result
11
+
12
+ def env
13
+ @env
14
+ end
15
+
16
+ RUBY_EVAL
10
17
  env[:body].instance_eval { @env = env }
11
18
  end
12
19
 
@@ -16,6 +16,9 @@ module Github
16
16
  raise Github::Forbidden.new(response_message(env), env[:response_headers])
17
17
  when 404
18
18
  raise Github::ResourceNotFound.new(response_message(env), env[:response_headers])
19
+
20
+ when 422
21
+ raise Github::UnprocessableEntitty.new(response_message(env), env[:response_headers])
19
22
  when 500
20
23
  raise Github::InternalServerError.new(response_message(env), env[:response_headers])
21
24
  when 503
@@ -2,16 +2,17 @@
2
2
 
3
3
  module Github
4
4
  module Result
5
+ include Github::Constants
5
6
 
6
- RATELIMIT = 'X-RateLimit-Remaining'.freeze
7
- CONTENT_TYPE = 'Content-Type'.freeze
8
- CONTENT_LENGTH = 'content-length'.freeze
9
-
10
- attr_reader :env
7
+ # TODO Add result counts method to check total items looking at result links
11
8
 
12
9
  # Requests are limited to API v3 to 5000 per hour.
13
- def ratelimit
14
- loaded? ? @env[:response_headers][RATELIMIT] : nil
10
+ def ratelimit_limit
11
+ loaded? ? @env[:response_headers][RATELIMIT_LIMIT] : nil
12
+ end
13
+
14
+ def ratelimit_remaining
15
+ loaded? ? @env[:response_headers][RATELIMIT_REMAINING] : nil
15
16
  end
16
17
 
17
18
  def content_type
@@ -30,12 +31,89 @@ module Github
30
31
  (200..299).include? status
31
32
  end
32
33
 
34
+ # Returns raw body
33
35
  def body
34
36
  loaded? ? @env[:body] : nil
35
37
  end
36
38
 
37
39
  def loaded?
38
- !!env
40
+ !!@env
41
+ end
42
+
43
+ # Return page links
44
+ def links
45
+ @@links = Github::PageLinks.new(@env[:response_headers])
46
+ end
47
+
48
+ # Iterator like each for response pages. If there are no pages to
49
+ # iterate over this method will return nothing.
50
+ def each_page
51
+ while page_iterator.has_next?
52
+ yield next_page #page_iterator.next
53
+ end
54
+ end
55
+
56
+ # Retrives the result of the first page. Returns <tt>nil</tt> if there is
57
+ # no first page - either because you are already on the first page
58
+ # or there are no pages at all in the result.
59
+ def first_page
60
+ first_request = page_iterator.first
61
+ self.instance_eval { @env = first_request.env } if first_request
62
+ first_request
63
+ end
64
+
65
+ # Retrives the result of the next page. Returns <tt>nil</tt> if there is
66
+ # no next page or no pages at all.
67
+ def next_page
68
+ next_request = page_iterator.next
69
+ self.instance_eval { @env = next_request.env } if next_request
70
+ next_request
71
+ end
72
+
73
+ # Retrives the result of the previous page. Returns <tt>nil</tt> if there is
74
+ # no previous page or no pages at all.
75
+ def prev_page
76
+ prev_request = page_iterator.prev
77
+ self.instance_eval { @env = prev_request.env } if prev_request
78
+ prev_request
79
+ end
80
+ alias :previous_page :prev_page
81
+
82
+ # Retrives the result of the last page. Returns <tt>nil</tt> if there is
83
+ # no last page - either because you are already on the last page,
84
+ # there is only one page or there are no pages at all in the result.
85
+ def last_page
86
+ last_request = page_iterator.last
87
+ self.instance_eval { @env = last_request.env } if last_request
88
+ last_request
89
+ end
90
+
91
+ # Retrives a specific result for a page given page number.
92
+ # The <tt>page_number</tt> parameter is not validate, hitting a page
93
+ # that does not exist will return Github API error. Consequently, if
94
+ # there is only one page, this method returns nil
95
+ def page(page_number)
96
+ request = page_iterator.get_page(page_number)
97
+ self.instance_eval { @env = request.env } if request
98
+ request
99
+ end
100
+
101
+ # Returns <tt>true</tt> if there is another page in the result set,
102
+ # otherwise <tt>false</tt>
103
+ def has_next_page?
104
+ page_iterator.has_next?
105
+ end
106
+
107
+ # Repopulates objects for new values
108
+ def reset
109
+ nil
110
+ end
111
+
112
+ private
113
+
114
+ # Internally used page iterator
115
+ def page_iterator # :nodoc:
116
+ @@page_iterator = Github::PageIterator.new(@env)
39
117
  end
40
118
 
41
119
  end # Result
@@ -0,0 +1,46 @@
1
+ require 'cgi'
2
+
3
+ module Github
4
+ module Utils
5
+ module Url
6
+ extend self
7
+
8
+ DEFAULT_QUERY_SEP = /[&;] */n
9
+
10
+ KEY_VALUE_SEP = '='.freeze
11
+
12
+ def escape(s) CGI.escape s.to_s end
13
+
14
+ def unescape(s) CGI.unescape s.to_s end
15
+
16
+ def parse_query(query_string)
17
+ return '' if query_string.nil? || query_string.empty?
18
+ params = {}
19
+
20
+ query_string.split(DEFAULT_QUERY_SEP).each do |part|
21
+ k, v = part.split(KEY_VALUE_SEP, 2).map { |el| unescape(el) }
22
+
23
+ if cur = params[k]
24
+ if cur.class == Array
25
+ params[k] << v
26
+ else
27
+ params[k] = [cur, v]
28
+ end
29
+ else
30
+ params[k] = v
31
+ end
32
+ end
33
+ params
34
+ end
35
+
36
+ def parse_query_for_param(query_string, name)
37
+ parse_query(query_string).each do |key, val|
38
+ return val.first if (name == key) && val.is_a?(Array)
39
+ return val if (name == key)
40
+ end
41
+ return nil
42
+ end
43
+
44
+ end # Url
45
+ end # Utils
46
+ end # Github
@@ -3,8 +3,8 @@
3
3
  module Github
4
4
  module VERSION
5
5
  MAJOR = 0
6
- MINOR = 3
7
- PATCH = 9
6
+ MINOR = 4
7
+ PATCH = 0
8
8
  BUILD = nil
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.');
data/spec/README.rdoc CHANGED
@@ -9,6 +9,10 @@ To run the specs first run the +bundle+ command to install the necessary gems an
9
9
 
10
10
  The specs currently require Ruby 1.9.x.
11
11
 
12
+ In order to run only features
13
+
14
+ rake features
15
+
12
16
  == Coverage
13
17
 
14
18
  GithubAPI will run coverage only on demand and to run it do
@@ -0,0 +1,189 @@
1
+ require 'spec_helper'
2
+
3
+ describe Github::PageIterator do
4
+
5
+ let(:link) {
6
+ "<https://api.github.com/users/wycats/repos?page=4&per_page=20>; rel=\"next\", <https://api.github.com/users/wycats/repos?page=6&per_page=20>; rel=\"last\", <https://api.github.com/users/wycats/repos?page=1&per_page=20>; rel=\"first\", <https://api.github.com/users/wycats/repos?page=2&per_page=20>; rel=\"prev\""
7
+ }
8
+ let(:env) { { :response_headers => {'Link' => link } } }
9
+ let(:first) { "https://api.github.com/users/wycats/repos?page=1&per_page=20" }
10
+ let(:nexxt) { "https://api.github.com/users/wycats/repos?page=4&per_page=20" }
11
+ let(:prev) { "https://api.github.com/users/wycats/repos?page=2&per_page=20" }
12
+ let(:last) { "https://api.github.com/users/wycats/repos?page=6&per_page=20" }
13
+ let(:user) { 'wycats' }
14
+
15
+ let(:instance) { Github::PageIterator.new(env) }
16
+
17
+ it { described_class::ATTRIBUTES.should_not be_nil }
18
+
19
+ context 'initialization' do
20
+
21
+ it { instance.first_page.should eq 1 }
22
+ it { instance.first_page_uri.should eq first }
23
+ it { instance.next_page.should eq 4 }
24
+ it { instance.next_page_uri.should eq nexxt }
25
+ it { instance.prev_page.should eq 2 }
26
+ it { instance.prev_page_uri.should eq prev }
27
+ it { instance.last_page.should eql 6 }
28
+ it { instance.last_page_uri.should eq last }
29
+
30
+ end
31
+
32
+ context 'has_next?' do
33
+ it "return true when next_page_uri is present" do
34
+ instance.has_next?.should be_true
35
+ end
36
+
37
+ it "returns false when next_page_uri is nil" do
38
+ instance.should_receive(:next_page_uri).and_return nil
39
+ instance.has_next?.should be_false
40
+ end
41
+ end
42
+
43
+ context 'first' do
44
+ before do
45
+ Github.new
46
+ instance.stub(:has_next?).and_return true
47
+ stub_get("/users/#{user}/repos").
48
+ with(:query => { 'per_page' => '20'}).
49
+ to_return(:body => '', :status => 200,
50
+ :headers => {
51
+ :content_type => "application/json; charset=utf-8",
52
+ 'Link' => link
53
+ }
54
+ )
55
+ end
56
+
57
+ it 'returns nil if there are no more pages' do
58
+ instance.stub(:first_page_uri).and_return false
59
+ instance.first.should be_nil
60
+ end
61
+
62
+ it 'performs request' do
63
+ link.stub(:links).and_return link
64
+ instance.stub(:update_page_links)
65
+ instance.should_receive(:page_request).
66
+ with("https://api.github.com/users/#{user}/repos", 'per_page' => 20).
67
+ and_return link
68
+ instance.first
69
+ end
70
+ end # first
71
+
72
+ context 'next' do
73
+ before do
74
+ Github.new
75
+ instance.stub(:has_next?).and_return true
76
+ stub_get("/users/#{user}/repos").
77
+ with(:query => { 'page' => '4', 'per_page' => '20'}).
78
+ to_return(:body => '', :status => 200,
79
+ :headers => {
80
+ :content_type => "application/json; charset=utf-8",
81
+ 'Link' => link
82
+ }
83
+ )
84
+ end
85
+
86
+ it 'returns nil if there are no more pages' do
87
+ instance.stub(:has_next?).and_return false
88
+ instance.next.should be_nil
89
+ end
90
+
91
+ it 'performs request' do
92
+ link.stub(:links).and_return link
93
+ instance.stub(:update_page_links)
94
+ instance.should_receive(:page_request).
95
+ with("https://api.github.com/users/#{user}/repos",
96
+ 'page' => 4,'per_page' => 20).and_return link
97
+ instance.next
98
+ end
99
+ end # next
100
+
101
+ context 'prev' do
102
+ before do
103
+ Github.new
104
+ instance.stub(:has_next?).and_return true
105
+ stub_get("/users/#{user}/repos").
106
+ with(:query => { 'page' => '2', 'per_page' => '20'}).
107
+ to_return(:body => '', :status => 200,
108
+ :headers => {
109
+ :content_type => "application/json; charset=utf-8",
110
+ 'Link' => link
111
+ }
112
+ )
113
+ end
114
+
115
+ it 'returns nil if there are no previous pages' do
116
+ instance.stub(:prev_page_uri).and_return false
117
+ instance.prev.should be_nil
118
+ end
119
+
120
+ it 'performs request' do
121
+ link.stub(:links).and_return link
122
+ instance.stub(:update_page_links)
123
+ instance.should_receive(:page_request).
124
+ with("https://api.github.com/users/#{user}/repos",
125
+ 'page' => 2,'per_page' => 20).and_return link
126
+ instance.prev
127
+ end
128
+ end # prev
129
+
130
+ context 'last' do
131
+ before do
132
+ Github.new
133
+ instance.stub(:has_next?).and_return true
134
+ stub_get("/users/#{user}/repos").
135
+ with(:query => { 'page' => '6', 'per_page' => '20'}).
136
+ to_return(:body => '', :status => 200,
137
+ :headers => {
138
+ :content_type => "application/json; charset=utf-8",
139
+ 'Link' => link
140
+ }
141
+ )
142
+ end
143
+
144
+ it 'returns nil if there is not last page' do
145
+ instance.stub(:last_page_uri).and_return false
146
+ instance.last.should be_nil
147
+ end
148
+
149
+ it 'performs request' do
150
+ link.stub(:links).and_return link
151
+ instance.stub(:update_page_links)
152
+ instance.should_receive(:page_request).
153
+ with("https://api.github.com/users/#{user}/repos",
154
+ 'page' => 6,'per_page' => 20).and_return link
155
+ instance.last
156
+ end
157
+ end # last
158
+
159
+ context 'get_page' do
160
+ before do
161
+ Github.new
162
+ instance.stub(:has_next?).and_return true
163
+ stub_get("/users/#{user}/repos").
164
+ with(:query => { 'page' => '6', 'per_page' => '20'}).
165
+ to_return(:body => '', :status => 200,
166
+ :headers => {
167
+ :content_type => "application/json; charset=utf-8",
168
+ 'Link' => link
169
+ }
170
+ )
171
+ end
172
+
173
+ it 'returns nil if there are no pages' do
174
+ instance.stub(:first_page_uri).and_return nil
175
+ instance.stub(:last_page_uri).and_return nil
176
+ instance.get_page(5).should be_nil
177
+ end
178
+
179
+ it 'finds a single page' do
180
+ instance.should_receive(:update_page_links)
181
+ instance.should_receive(:page_request).
182
+ with("https://api.github.com/users/#{user}/repos",
183
+ 'page' => 2, 'per_page' => 20).and_return link
184
+ link.stub(:links).and_return link
185
+ instance.get_page(2)
186
+ end
187
+ end # get_page
188
+
189
+ end # Github::PageIterator