gh 0.6.1 → 0.7.1
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.
- data/.travis.yml +2 -2
- data/README.md +4 -1
- data/gh.gemspec +1 -1
- data/lib/gh.rb +14 -6
- data/lib/gh/cache.rb +2 -2
- data/lib/gh/error.rb +11 -1
- data/lib/gh/merge_commit.rb +1 -1
- data/lib/gh/parallel.rb +4 -1
- data/lib/gh/remote.rb +8 -9
- data/lib/gh/response.rb +6 -2
- data/lib/gh/version.rb +1 -1
- data/lib/gh/wrapper.rb +7 -3
- data/spec/gh_spec.rb +8 -0
- data/spec/normalizer_spec.rb +1 -1
- data/spec/parallel_spec.rb +24 -0
- data/spec/response_spec.rb +2 -3
- data/spec/spec_helper.rb +3 -2
- metadata +20 -19
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -13,13 +13,16 @@ This will by default use all the middleware that ships with GH, in the following
|
|
13
13
|
|
14
14
|
* `GH::Remote` - sends HTTP requests to GitHub and parses the response
|
15
15
|
* `GH::Normalizer` - renames fields consistenly, adds hypermedia links if possible
|
16
|
-
* `GH::Cache` - caches the responses (will use Rails cache if in Rails, in-memory cache otherwise)
|
17
16
|
* `GH::LazyLoader` - will load missing fields when accessed (handy for dealing with incomplete data without sending to many requests)
|
18
17
|
* `GH::MergeCommit` - adds infos about merge commits to pull request payloads
|
19
18
|
* `GH::LinkFollower` - will add content of hypermedia links as fields (lazyly), allows you to traverse relations
|
20
19
|
* `GH::Pagination` - adds support for transparent pagination
|
21
20
|
* `GH::Instrumentation` - let's you instrument `gh`
|
22
21
|
|
22
|
+
The following middleware is not included by default:
|
23
|
+
|
24
|
+
* `GH::Cache` - caches the responses (will use Rails cache if in Rails, in-memory cache otherwise)
|
25
|
+
|
23
26
|
## Main Entry Points
|
24
27
|
|
25
28
|
Every layer has two main entry points:
|
data/gh.gemspec
CHANGED
@@ -23,6 +23,6 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_runtime_dependency 'backports', '~> 2.3'
|
24
24
|
s.add_runtime_dependency 'multi_json', '~> 1.0'
|
25
25
|
s.add_runtime_dependency 'addressable'
|
26
|
-
s.add_runtime_dependency 'net-http-persistent'
|
26
|
+
s.add_runtime_dependency 'net-http-persistent', '>= 2.7'
|
27
27
|
s.add_runtime_dependency 'net-http-pipeline'
|
28
28
|
end
|
data/lib/gh.rb
CHANGED
@@ -21,11 +21,20 @@ module GH
|
|
21
21
|
autoload :Wrapper, 'gh/wrapper'
|
22
22
|
|
23
23
|
def self.with(backend)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
if Hash === backend
|
25
|
+
@options ||= {}
|
26
|
+
@options, options = @options.merge(backend), @options
|
27
|
+
backend = DefaultStack.build(@options)
|
28
|
+
end
|
29
|
+
|
30
|
+
if block_given?
|
31
|
+
was, self.current = current, backend
|
32
|
+
yield
|
33
|
+
else
|
34
|
+
backend
|
35
|
+
end
|
28
36
|
ensure
|
37
|
+
@options = options if options
|
29
38
|
self.current = was if was
|
30
39
|
end
|
31
40
|
|
@@ -38,7 +47,7 @@ module GH
|
|
38
47
|
end
|
39
48
|
|
40
49
|
extend SingleForwardable
|
41
|
-
def_delegators :current, :api_host, :[], :reset, :load, :post, :delete, :patch, :put, :in_parallel, :in_parallel
|
50
|
+
def_delegators :current, :api_host, :[], :reset, :load, :post, :delete, :patch, :put, :in_parallel, :in_parallel?, :options
|
42
51
|
|
43
52
|
DefaultStack = Stack.new do
|
44
53
|
use Instrumentation
|
@@ -47,7 +56,6 @@ module GH
|
|
47
56
|
use LinkFollower
|
48
57
|
use MergeCommit
|
49
58
|
use LazyLoader
|
50
|
-
use Cache
|
51
59
|
use Normalizer
|
52
60
|
use Remote
|
53
61
|
end
|
data/lib/gh/cache.rb
CHANGED
@@ -31,8 +31,8 @@ module GH
|
|
31
31
|
|
32
32
|
# Internal: Initializes a new Cache instance.
|
33
33
|
def setup(*)
|
34
|
-
self.cache ||= Rails.cache if defined? Rails.cache and defined? RAILS_CACHE
|
35
|
-
self.cache ||= ActiveSupport::Cache.lookup_store if defined? ActiveSupport::Cache.lookup_store
|
34
|
+
#self.cache ||= Rails.cache if defined? Rails.cache and defined? RAILS_CACHE
|
35
|
+
#self.cache ||= ActiveSupport::Cache.lookup_store if defined? ActiveSupport::Cache.lookup_store
|
36
36
|
self.cache ||= SimpleCache.new
|
37
37
|
super
|
38
38
|
end
|
data/lib/gh/error.rb
CHANGED
@@ -4,6 +4,10 @@ module GH
|
|
4
4
|
class Error < Exception
|
5
5
|
attr_reader :error, :payload
|
6
6
|
|
7
|
+
def self.new(error, *)
|
8
|
+
Error === error ? error : super
|
9
|
+
end
|
10
|
+
|
7
11
|
def initialize(error = nil, payload = nil)
|
8
12
|
error = error.error while error.respond_to? :error
|
9
13
|
@error, @payload = error, payload
|
@@ -11,7 +15,13 @@ module GH
|
|
11
15
|
end
|
12
16
|
|
13
17
|
def message
|
14
|
-
"GH request failed (#{error.message}) with payload: #{payload.inspect}"
|
18
|
+
"GH request failed (#{error.class}: #{error.message}) with payload: #{short(payload.inspect)}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def short(string)
|
24
|
+
string.length < 101 ? string : string[0,97] + '...'
|
15
25
|
end
|
16
26
|
end
|
17
27
|
end
|
data/lib/gh/merge_commit.rb
CHANGED
@@ -52,7 +52,7 @@ module GH
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def force_merge_commit(hash)
|
55
|
-
Timeout.timeout(
|
55
|
+
Timeout.timeout(600) do # MAGIC NUMBERS FTW
|
56
56
|
# FIXME: Rick said "this will become part of the API"
|
57
57
|
# until then, please look the other way
|
58
58
|
while hash['mergeable'].nil?
|
data/lib/gh/parallel.rb
CHANGED
@@ -5,6 +5,8 @@ require 'backports/basic_object' unless defined? BasicObject
|
|
5
5
|
module GH
|
6
6
|
# Public: ...
|
7
7
|
class Parallel < Wrapper
|
8
|
+
attr_accessor :parallelize
|
9
|
+
|
8
10
|
class Dummy < BasicObject
|
9
11
|
attr_accessor :__delegate__
|
10
12
|
def method_missing(*args)
|
@@ -14,6 +16,7 @@ module GH
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def setup(*)
|
19
|
+
@parallelize = true if @parallelize.nil?
|
17
20
|
@in_parallel = false
|
18
21
|
@mutex = Mutex.new
|
19
22
|
@queue = []
|
@@ -28,7 +31,7 @@ module GH
|
|
28
31
|
end
|
29
32
|
|
30
33
|
def in_parallel
|
31
|
-
return yield if in_parallel?
|
34
|
+
return yield if in_parallel? or not @parallelize
|
32
35
|
was, @in_parallel = @in_parallel, true
|
33
36
|
result = nil
|
34
37
|
connection.in_parallel { result = yield }
|
data/lib/gh/remote.rb
CHANGED
@@ -42,16 +42,12 @@ module GH
|
|
42
42
|
faraday_options[:ssl] = options[:ssl] if options[:ssl]
|
43
43
|
faraday_options.merge! options[:faraday_options] if options[:faraday_options]
|
44
44
|
|
45
|
-
adapter = options[:adapter]
|
46
|
-
adapter ||= Faraday::Adapter::NetHttp if defined? RUBY_ENGINE and RUBY_ENGINE == 'jruby'
|
47
|
-
adapter ||= GH::FaradayAdapter
|
48
|
-
|
49
45
|
@connection = Faraday.new(faraday_options) do |builder|
|
50
46
|
builder.request(:authorization, :token, token) if token
|
51
47
|
builder.request(:basic_auth, username, password) if username and password
|
52
48
|
builder.request(:retry)
|
53
49
|
builder.response(:raise_error)
|
54
|
-
builder.use(adapter)
|
50
|
+
builder.use(options[:adapter] || GH::FaradayAdapter)
|
55
51
|
end
|
56
52
|
end
|
57
53
|
|
@@ -67,7 +63,10 @@ module GH
|
|
67
63
|
|
68
64
|
# Internal: ...
|
69
65
|
def generate_response(key, response)
|
70
|
-
|
66
|
+
body, headers = response.body, response.headers
|
67
|
+
url = response.respond_to?(:url) ? response.url : response.env.try(:[], :url)
|
68
|
+
url = full_url(key) if url.to_s.empty?
|
69
|
+
modify(body, headers, url)
|
71
70
|
end
|
72
71
|
|
73
72
|
# Internal: ...
|
@@ -78,7 +77,7 @@ module GH
|
|
78
77
|
# Internal: ...
|
79
78
|
def request(verb, key, body = nil)
|
80
79
|
response = frontend.http(verb, path_for(key), headers) do |req|
|
81
|
-
req.body = Response.new(
|
80
|
+
req.body = Response.new(body).to_s if body
|
82
81
|
end
|
83
82
|
frontend.generate_response(key, response)
|
84
83
|
end
|
@@ -123,9 +122,9 @@ module GH
|
|
123
122
|
path_for(key)
|
124
123
|
end
|
125
124
|
|
126
|
-
def modify(body, headers = {})
|
125
|
+
def modify(body, headers = {}, url = nil)
|
127
126
|
return body if body.is_a? Response
|
128
|
-
Response.new(headers,
|
127
|
+
Response.new(body, headers, url)
|
129
128
|
end
|
130
129
|
end
|
131
130
|
end
|
data/lib/gh/response.rb
CHANGED
@@ -12,7 +12,7 @@ module GH
|
|
12
12
|
CONTENT_TYPE = "application/json; charset=utf-8"
|
13
13
|
|
14
14
|
include Enumerable
|
15
|
-
attr_accessor :headers, :data, :body
|
15
|
+
attr_accessor :headers, :data, :body, :url
|
16
16
|
|
17
17
|
# subset of safe methods that both Array and Hash implement
|
18
18
|
extend Forwardable
|
@@ -23,8 +23,10 @@ module GH
|
|
23
23
|
#
|
24
24
|
# headers - HTTP headers as a Hash
|
25
25
|
# body - HTTP body as a String
|
26
|
-
def initialize(
|
26
|
+
def initialize(body = "{}", headers = {}, url = nil)
|
27
|
+
@url = url
|
27
28
|
@headers = Hash[headers.map { |k,v| [k.downcase, v] }]
|
29
|
+
|
28
30
|
raise ArgumentError, "unexpected Content-Type #{content_type}" if content_type and content_type != CONTENT_TYPE
|
29
31
|
|
30
32
|
case body
|
@@ -38,6 +40,8 @@ module GH
|
|
38
40
|
@body.force_encoding("utf-8") if @body.respond_to? :force_encoding
|
39
41
|
@body ||= MultiJson.encode(@data)
|
40
42
|
@data ||= MultiJson.decode(@body)
|
43
|
+
rescue EncodingError => error
|
44
|
+
fail "Invalid encoding in #{url.to_s}, please contact github."
|
41
45
|
end
|
42
46
|
|
43
47
|
# Public: Duplicates the instance. Will also duplicate some instance variables to behave as expected.
|
data/lib/gh/version.rb
CHANGED
data/lib/gh/wrapper.rb
CHANGED
@@ -27,6 +27,9 @@ module GH
|
|
27
27
|
# Public: Get wrapped layer.
|
28
28
|
attr_reader :backend
|
29
29
|
|
30
|
+
# Public: ...
|
31
|
+
attr_reader :options
|
32
|
+
|
30
33
|
# Public: Returns the URI used for sending out web request.
|
31
34
|
def_delegator :backend, :api_host
|
32
35
|
|
@@ -86,8 +89,9 @@ module GH
|
|
86
89
|
# backend - layer to be wrapped
|
87
90
|
# options - config options
|
88
91
|
def initialize(backend = nil, options = {})
|
89
|
-
|
90
|
-
options.each_pair { |key, value| public_send("#{key}=", value) if respond_to? "#{key}=" }
|
92
|
+
backend, @options = normalize_options(backend, options)
|
93
|
+
@options.each_pair { |key, value| public_send("#{key}=", value) if respond_to? "#{key}=" }
|
94
|
+
setup(backend, @options)
|
91
95
|
end
|
92
96
|
|
93
97
|
# Public: Set wrapped layer.
|
@@ -156,7 +160,7 @@ module GH
|
|
156
160
|
|
157
161
|
def modify_response(response)
|
158
162
|
result = double_dispatch response.data
|
159
|
-
result.respond_to?(:to_gh) ? result.to_gh : Response.new(response.headers,
|
163
|
+
result.respond_to?(:to_gh) ? result.to_gh : Response.new(result, response.headers, response.url)
|
160
164
|
end
|
161
165
|
|
162
166
|
def modify(data, *)
|
data/spec/gh_spec.rb
CHANGED
@@ -20,5 +20,13 @@ describe GH do
|
|
20
20
|
it 'returns the block value if block is given' do
|
21
21
|
GH.with(:token => "...") { 42 }.should be == 42
|
22
22
|
end
|
23
|
+
|
24
|
+
it 'propagates options' do
|
25
|
+
GH.with(:a => :b) do
|
26
|
+
GH.with(:b => :c) do
|
27
|
+
GH.options.should be == {:a => :b, :b => :c}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
23
31
|
end
|
24
32
|
end
|
data/spec/normalizer_spec.rb
CHANGED
data/spec/parallel_spec.rb
CHANGED
@@ -44,6 +44,30 @@ describe GH::Parallel do
|
|
44
44
|
GH.should_not be_in_parallel
|
45
45
|
end
|
46
46
|
|
47
|
+
it 'runs requests right away if parallelize is set to false' do
|
48
|
+
WebMock.allow_net_connect!
|
49
|
+
GH::DefaultStack.replace GH::MockBackend, GH::Remote
|
50
|
+
GH.with :parallelize => false do
|
51
|
+
GH.should_not be_in_parallel
|
52
|
+
|
53
|
+
a = b = nil
|
54
|
+
GH.in_parallel do
|
55
|
+
GH.should_not be_in_parallel
|
56
|
+
|
57
|
+
a = GH['users/rkh']
|
58
|
+
b = GH['users/svenfuchs']
|
59
|
+
|
60
|
+
a['name'].should be == "Konstantin Haase"
|
61
|
+
b['name'].should be == "Sven Fuchs"
|
62
|
+
end
|
63
|
+
|
64
|
+
a['name'].should be == "Konstantin Haase"
|
65
|
+
b['name'].should be == "Sven Fuchs"
|
66
|
+
|
67
|
+
GH.should_not be_in_parallel
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
47
71
|
it 'returns the block value' do
|
48
72
|
GH.in_parallel { 42 }.should be == 42
|
49
73
|
end
|
data/spec/response_spec.rb
CHANGED
@@ -5,12 +5,11 @@ describe GH::Response do
|
|
5
5
|
it 'handles UTF-8 properly, even if encoded binary' do
|
6
6
|
raw = '{"foo":"über cool sista året"}'
|
7
7
|
raw.force_encoding 'binary' if raw.respond_to? :force_encoding
|
8
|
-
response = GH::Response.new(
|
8
|
+
response = GH::Response.new(raw)
|
9
9
|
response['foo'].should be == 'über cool sista året'
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'handles broken encodings properly' do
|
13
|
-
|
14
|
-
GH::Response.new({}, "{\"foo\":\"\xC3\"}")["foo"].should be == "\xC3"
|
13
|
+
GH::Response.new("{\"foo\":\"\xC3\"}")["foo"].should be == "\xC3"
|
15
14
|
end
|
16
15
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -51,10 +51,11 @@ module GH
|
|
51
51
|
File.write file, [res.headers, res.body].to_yaml
|
52
52
|
end
|
53
53
|
|
54
|
-
|
54
|
+
headers, body = YAML.load_file(file)
|
55
|
+
Response.new(body, headers, full_url(key))
|
55
56
|
end
|
56
57
|
|
57
|
-
result = Response.new(
|
58
|
+
result = Response.new(result) unless result.is_a? Response
|
58
59
|
result
|
59
60
|
end
|
60
61
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70105565578080 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70105565578080
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: webmock
|
27
|
-
requirement: &
|
27
|
+
requirement: &70105565576840 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70105565576840
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: faraday
|
38
|
-
requirement: &
|
38
|
+
requirement: &70105565576200 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0.8'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70105565576200
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: backports
|
49
|
-
requirement: &
|
49
|
+
requirement: &70105565586200 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '2.3'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70105565586200
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: multi_json
|
60
|
-
requirement: &
|
60
|
+
requirement: &70105565583400 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '1.0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70105565583400
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: addressable
|
71
|
-
requirement: &
|
71
|
+
requirement: &70105565597220 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,21 +76,21 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70105565597220
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: net-http-persistent
|
82
|
-
requirement: &
|
82
|
+
requirement: &70105565595200 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
87
|
+
version: '2.7'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70105565595200
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: net-http-pipeline
|
93
|
-
requirement: &
|
93
|
+
requirement: &70105565593540 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :runtime
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70105565593540
|
102
102
|
description: multi-layer client for the github api v3
|
103
103
|
email:
|
104
104
|
- konstantin.mailinglists@googlemail.com
|
@@ -230,3 +230,4 @@ test_files:
|
|
230
230
|
- spec/spec_helper.rb
|
231
231
|
- spec/stack_spec.rb
|
232
232
|
- spec/wrapper_spec.rb
|
233
|
+
has_rdoc:
|