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.
@@ -7,10 +7,10 @@ rvm:
7
7
  - jruby-19mode
8
8
  - rbx-18mode
9
9
  - rbx-19mode
10
- - ruby-head
11
10
  - jruby-head
12
11
  - ree
13
12
  matrix:
14
13
  allow_failures:
14
+ - rvm: jruby-18mode
15
+ - rvm: jruby-19mode
15
16
  - rvm: jruby-head
16
- - rvm: ruby-head
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
- backend = DefaultStack.build(backend) if Hash === backend
25
- return backend unless block_given?
26
- was, self.current = current, backend
27
- yield
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
@@ -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
@@ -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
@@ -52,7 +52,7 @@ module GH
52
52
  end
53
53
 
54
54
  def force_merge_commit(hash)
55
- Timeout.timeout(10) do # MAGIC NUMBERS FTW
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?
@@ -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 }
@@ -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
- modify(response.body, response.headers)
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({}, body).to_s if body
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, body)
127
+ Response.new(body, headers, url)
129
128
  end
130
129
  end
131
130
  end
@@ -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(headers = {}, body = "{}")
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.
@@ -1,4 +1,4 @@
1
1
  module GH
2
2
  # Public: Library version.
3
- VERSION = "0.6.1"
3
+ VERSION = "0.7.1"
4
4
  end
@@ -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
- setup(*normalize_options(backend, options))
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, result)
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, *)
@@ -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
@@ -8,7 +8,7 @@ describe GH::Normalizer do
8
8
  end
9
9
 
10
10
  def with_headers(headers = {})
11
- response = GH::Response.new(headers)
11
+ response = GH::Response.new("{}", headers)
12
12
  data['/payload'], response.data = response, data['/payload']
13
13
  end
14
14
 
@@ -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
@@ -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({}, raw)
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
- pending if RUBY_ENGINE == 'jruby' # see https://github.com/flori/json/issues/138
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
@@ -51,10 +51,11 @@ module GH
51
51
  File.write file, [res.headers, res.body].to_yaml
52
52
  end
53
53
 
54
- Response.new(*YAML.load_file(file))
54
+ headers, body = YAML.load_file(file)
55
+ Response.new(body, headers, full_url(key))
55
56
  end
56
57
 
57
- result = Response.new({}, result) unless result.is_a? Response
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.6.1
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-06 00:00:00.000000000 Z
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: &70100388987640 !ruby/object:Gem::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: *70100388987640
24
+ version_requirements: *70105565578080
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: webmock
27
- requirement: &70100388987220 !ruby/object:Gem::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: *70100388987220
35
+ version_requirements: *70105565576840
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: faraday
38
- requirement: &70100388986720 !ruby/object:Gem::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: *70100388986720
46
+ version_requirements: *70105565576200
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: backports
49
- requirement: &70100388986220 !ruby/object:Gem::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: *70100388986220
57
+ version_requirements: *70105565586200
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: multi_json
60
- requirement: &70100386169740 !ruby/object:Gem::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: *70100386169740
68
+ version_requirements: *70105565583400
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: addressable
71
- requirement: &70100386169360 !ruby/object:Gem::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: *70100386169360
79
+ version_requirements: *70105565597220
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: net-http-persistent
82
- requirement: &70100386168900 !ruby/object:Gem::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: '0'
87
+ version: '2.7'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *70100386168900
90
+ version_requirements: *70105565595200
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: net-http-pipeline
93
- requirement: &70100386168480 !ruby/object:Gem::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: *70100386168480
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: