github_api 0.3.9 → 0.4.0

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