gh 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -12,6 +12,5 @@ rvm:
12
12
  - ree
13
13
  matrix:
14
14
  allow_failures:
15
- - rvm: ruby-head
16
- - rvm: rbx-18mode
17
- - rvm: rbx-19mode
15
+ - rvm: jruby-19mode
16
+ - rvm: jruby-head
data/README.md CHANGED
@@ -1,38 +1,118 @@
1
- **This is work in progress and not yet usable!**
1
+ # GH - Layered GitHub API client
2
2
 
3
- Goal of this library is to ease usage of the Github API as part of large, tightly integrated, distributed projects, such as [Travis CI](http://travis-ci.org). It was born out due to issues we ran into with all existing Github libraries and the Github API itself.
3
+ This is a highly flexible, layered, low-level GitHub client library, trying to get out of your way and let you get to the GitHub data as simple as possible. Unless you add layers, you will end up with Hashes and Arrays. The approach and API should be familiar from projects like Rack or Faraday.
4
4
 
5
- With that in mind, this library follows the following goals:
5
+ Simple example:
6
6
 
7
- * Implement features in separate layers, make layers as independend of each other as possible
8
- * Higher level layers should not worry about when to send requests
9
- * It should only send requests to Github when necessary
10
- * It should be able to fetch data from Github asynchronously (i.e. HTTP requests to Travis should not be bound to HTTP requests to Github, if possible)
11
- * It should be able to deal with events and hooks well (i.e. update cached entities with hook data)
12
- * It should not have intransparent magic (i.e. implicit, undocumented requirements on fields we get from Github)
13
- * It should shield against possible changes to the Github API or at least complain about those changes if it can't deal with it.
7
+ ``` ruby
8
+ require 'gh'
9
+ puts GH['users/rkh']['name']
10
+ ```
11
+
12
+ This will by default use all the middleware that ships with GH, in the following order
13
+
14
+ * `GH::Remote` - sends HTTP requests to GitHub and parses the response
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
+ * `GH::LazyLoader` - will load missing fields when accessed (handy for dealing with incomplete data without sending to many requests)
18
+ * `GH::LinkFollower` - will add content of hypermedia links as fields (lazyly), allows you to traverse relations
19
+
20
+ ## Main Entry Points
21
+
22
+ Every layer has two main entry points:
23
+
24
+ * `[key]` - loads data from GitHub
25
+ * `load(data)` - takes data and applies modifications (handy for dealing with service hook payloads)
26
+
27
+ These two methods are exposed by any instance of a layer and the `GH` constant.
28
+
29
+ ## Using a Single Layer
30
+
31
+ You can initialize and use any layer on its own:
32
+
33
+ ``` ruby
34
+ gh = GH::Remote.new
35
+ puts gh['users/rkh']['name']
36
+ ```
37
+
38
+ Layers know which other layer they should usually wrap (`Remote` wraps no other layer, `LazyLoader` and `LinkFollower` wrap `Normalizer` by default, anything else wraps `Remote`), so you can initialize them right away:
39
+
40
+ ``` ruby
41
+ gh = GH::LazyLoader.new
42
+ ```
43
+
44
+ You can also pass the layer that should be wrapped as an argument:
45
+
46
+ ``` ruby
47
+ gh = GH::LazyLoader.new(GH::LinkFollower.new)
48
+ ```
49
+
50
+ ## Creating Your Own Stack
51
+
52
+ For convinience a stack DSL is provided:
14
53
 
15
- Most of this is not yet implemented!
54
+ ``` ruby
55
+ gh = GH::Stack.build do
56
+ use GH::Normalizer
57
+ use GH::Cache
58
+ end
16
59
 
17
- The lower level APIs support a Rack-like stacking API:
60
+ puts gh['users/rkh']['name']
61
+ ```
62
+
63
+ You can also create reusable `Stack` instances:
18
64
 
19
65
  ``` ruby
20
- api = GH::Stack.build do
21
- use GH::Cache, cache: Rails.cache
66
+ stack = GH::Stack.new do
22
67
  use GH::Normalizer
23
- use GH::Remote, username: "admin", password: "admin"
68
+ use GH::Cache
24
69
  end
70
+
71
+ gh = stack.build username: 'rkh', password: 'abc123'
72
+ puts gh['user']['name']
25
73
  ```
26
74
 
27
- Usage example:
75
+ One such instance (with the standard setup) can be accessed as `GH::DefaultStack`
76
+
77
+ ## Scoping
78
+
79
+ With the main goal to separate authentication from other logic, the `gh` library supports scopting:
28
80
 
29
81
  ``` ruby
30
- GH.with username: 'rkh', password: 'abc123' do
31
- sven = GH['users/svenfuchs']
82
+ GH.with GH::LazyLoader.new do
83
+ puts GH['users/rkh']['name']
84
+ end
85
+ ```
86
+
87
+ That way, you could create a stack with, for instance, an [access token](http://developer.github.com/v3/oauth/):
32
88
 
33
- if sven['hireable']
34
- # recruiter has to be provided by some different library
35
- Recruiter.contact sven['email']
36
- end
89
+ ``` ruby
90
+ authenticated = GH::DefaultStack token: 'e72e16c7e42f292c6912e7710c838347ae178b4a'
91
+
92
+ GH.with(authenticated) do
93
+ # ...
94
+ end
95
+ ```
96
+
97
+ Since this is rather common, you can pass options directly to `with`:
98
+
99
+ ``` ruby
100
+ GH.with(username: 'rkh', password: 'abc123') do
101
+ # ...
37
102
  end
38
103
  ```
104
+
105
+ Scoping is thread-safe.
106
+
107
+ ## Is this production ready?
108
+
109
+ I hope so, we use it in production for [Travis CI](http://travis-ci.org/). The work on this library has been funded by the [Travis Love Campaign](https://love.travis-ci.org/).
110
+
111
+ ## History
112
+
113
+ * 2012-04-10: 0.2.0 - added link following plus bug fixes (mainly encoding issues)
114
+ * 2012-04-06: 0.1.2 - bug fix release (issues with cache reloading)
115
+ * 2012-04-06: 0.1.1 - bug fix release (DSL fixes)
116
+ * 2012-04-04: 0.1.0 - many bug fixes plus lazy loading
117
+ * 2012-03-21: 0.0.1 - first public release
118
+ * 2012-03-05: project started
data/lib/gh.rb CHANGED
@@ -3,14 +3,15 @@ require 'backports'
3
3
  require 'forwardable'
4
4
 
5
5
  module GH
6
- autoload :Cache, 'gh/cache'
7
- autoload :Case, 'gh/case'
8
- autoload :LazyLoader, 'gh/lazy_loader'
9
- autoload :Normalizer, 'gh/normalizer'
10
- autoload :Remote, 'gh/remote'
11
- autoload :Response, 'gh/response'
12
- autoload :Stack, 'gh/stack'
13
- autoload :Wrapper, 'gh/wrapper'
6
+ autoload :Cache, 'gh/cache'
7
+ autoload :Case, 'gh/case'
8
+ autoload :LazyLoader, 'gh/lazy_loader'
9
+ autoload :LinkFollower, 'gh/link_follower'
10
+ autoload :Normalizer, 'gh/normalizer'
11
+ autoload :Remote, 'gh/remote'
12
+ autoload :Response, 'gh/response'
13
+ autoload :Stack, 'gh/stack'
14
+ autoload :Wrapper, 'gh/wrapper'
14
15
 
15
16
  def self.with(backend)
16
17
  backend = DefaultStack.build(backend) if Hash === backend
@@ -32,6 +33,7 @@ module GH
32
33
  def_delegators :current, :api_host, :[], :reset
33
34
 
34
35
  DefaultStack = Stack.new do
36
+ use LinkFollower
35
37
  use LazyLoader
36
38
  use Cache
37
39
  use Normalizer
@@ -0,0 +1,19 @@
1
+ module GH
2
+ class LinkFollower < Wrapper
3
+ wraps GH::Normalizer
4
+ double_dispatch
5
+
6
+ def modify_hash(hash)
7
+ hash = super
8
+ setup_lazy_loading(hash) if hash['_links']
9
+ hash
10
+ end
11
+
12
+ private
13
+
14
+ def lazy_load(hash, key)
15
+ link = hash['_links'][key]
16
+ { key => backend[link['href']] } if link
17
+ end
18
+ end
19
+ end
data/lib/gh/response.rb CHANGED
@@ -34,8 +34,8 @@ module GH
34
34
  else raise ArgumentError, "cannot parse #{body.inspect}"
35
35
  end
36
36
 
37
+ @body.force_encoding("utf-8") if @body.respond_to? :force_encoding
37
38
  @body ||= MultiJson.encode(@data)
38
- @body = @body.encode("utf-8") if @body.respond_to? :encode
39
39
  @data ||= MultiJson.decode(@body)
40
40
  end
41
41
 
data/lib/gh/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module GH
2
2
  # Public: Library version.
3
- VERSION = "0.1.2"
3
+ VERSION = "0.2.0"
4
4
  end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe GH::LinkFollower do
4
+ before { subject.backend = GH::Normalizer.new(GH::MockBackend.new) }
5
+
6
+ let(:pull_request) { subject['/repos/sinatra/sinatra/pulls/56'] }
7
+ let(:comments) { pull_request['comments'] }
8
+ let(:comment) { comments.first }
9
+ let(:commentator) { comment['owner'] }
10
+
11
+ it 'follows links' do
12
+ commentator['login'].should be == 'rtomayko'
13
+ end
14
+
15
+ it 'works with lazy loading' do
16
+ subject.backend = GH::LazyLoader.new(subject.backend)
17
+ # location is not included in the comment payload
18
+ commentator["location"].should be == "San Francisco"
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ ---
2
+ - !binary "c2VydmVy": !binary |-
3
+ bmdpbngvMS4wLjEz
4
+ !binary "ZGF0ZQ==": !binary |-
5
+ VHVlLCAxMCBBcHIgMjAxMiAxMTo1MzoxMiBHTVQ=
6
+ !binary "Y29udGVudC10eXBl": !binary |-
7
+ YXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOA==
8
+ !binary "dHJhbnNmZXItZW5jb2Rpbmc=": !binary |-
9
+ Y2h1bmtlZA==
10
+ !binary "Y29ubmVjdGlvbg==": !binary |-
11
+ a2VlcC1hbGl2ZQ==
12
+ !binary "c3RhdHVz": !binary |-
13
+ MjAwIE9L
14
+ !binary "eC1yYXRlbGltaXQtbGltaXQ=": !binary |-
15
+ NTAwMA==
16
+ !binary "ZXRhZw==": !binary |-
17
+ ImI5MDUzNGQ0Zjk3YTU0OGEwNTY1NWIyODg4OGM4YTZhIg==
18
+ !binary "eC1yYXRlbGltaXQtcmVtYWluaW5n": !binary |-
19
+ NDk5Mw==
20
+ - ! '[{"created_at":"2010-09-01T15:42:44Z","body":"This all looks good to me. Anyone
21
+ run the unit tests under 1.8.6, 1.8.7, 1.9.2?","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/383214","updated_at":"2010-09-01T15:42:44Z","user":{"gravatar_id":"abfc88b96ae18c85ba7aac3bded2ec5e","url":"https://api.github.com/users/rtomayko","login":"rtomayko","avatar_url":"https://secure.gravatar.com/avatar/abfc88b96ae18c85ba7aac3bded2ec5e?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":404},"id":383214},{"created_at":"2010-09-01T15:48:46Z","body":"Yep,
22
+ all pass. Even on JRuby 1.5.2. But on 1.9.2 they have to be run manually (see #52),
23
+ at least on my box. Same goes for current master, however.","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/383231","updated_at":"2010-09-01T16:00:16Z","user":{"gravatar_id":"5c2b452f6eea4a6d84c105ebd971d2a4","url":"https://api.github.com/users/rkh","login":"rkh","avatar_url":"https://secure.gravatar.com/avatar/5c2b452f6eea4a6d84c105ebd971d2a4?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":30442},"id":383231},{"created_at":"2010-09-01T16:16:08Z","body":"Hi,
24
+ why would you want to keep a version of Tilt bundled on Sinatra when Sinatra can
25
+ include Tilt as a dependency?","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/383302","updated_at":"2010-09-01T16:16:08Z","user":{"gravatar_id":"9d0d8afbcf75a57c86e41ba0fc6f8a98","url":"https://api.github.com/users/mr-rock","login":"mr-rock","avatar_url":"https://secure.gravatar.com/avatar/9d0d8afbcf75a57c86e41ba0fc6f8a98?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":23641},"id":383302},{"created_at":"2010-09-01T16:18:24Z","body":"Yeah.
26
+ I think the last time blake and I discussed tilt bundling, we decided to *not* bundle
27
+ it and just make it a dependency.","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/383307","updated_at":"2010-09-01T16:18:24Z","user":{"gravatar_id":"abfc88b96ae18c85ba7aac3bded2ec5e","url":"https://api.github.com/users/rtomayko","login":"rtomayko","avatar_url":"https://secure.gravatar.com/avatar/abfc88b96ae18c85ba7aac3bded2ec5e?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":404},"id":383307},{"created_at":"2010-09-01T16:21:54Z","body":"Lots
28
+ of goodies in here, particularly added support for scss views.","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/383320","updated_at":"2010-09-01T16:21:54Z","user":{"gravatar_id":"7fe945668a4fc098e886e20dea71d2ee","url":"https://api.github.com/users/zzak","login":"zzak","avatar_url":"https://secure.gravatar.com/avatar/7fe945668a4fc098e886e20dea71d2ee?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":277819},"id":383320},{"created_at":"2010-09-01T16:27:24Z","body":"@RTomayko:
29
+ I don''t see the point to repeat code that is going to be obsolete in some time
30
+ anyway. I already made a pull request in which Tilt is removed from Sinatra and
31
+ Tilt is a dependency of the gem. I tested it in Ruby 1.9.1 and it seems to work.","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/383334","updated_at":"2010-09-01T20:46:27Z","user":{"gravatar_id":"9d0d8afbcf75a57c86e41ba0fc6f8a98","url":"https://api.github.com/users/mr-rock","login":"mr-rock","avatar_url":"https://secure.gravatar.com/avatar/9d0d8afbcf75a57c86e41ba0fc6f8a98?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":23641},"id":383334},{"created_at":"2010-09-02T05:20:52Z","body":"@RTomayko:
32
+ Before Tilt is unbundled, could you please do another Tilt release? I think the
33
+ ScssTemplate hasn''t made it into 1.0.1.","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/384475","updated_at":"2010-09-02T05:20:52Z","user":{"gravatar_id":"5c2b452f6eea4a6d84c105ebd971d2a4","url":"https://api.github.com/users/rkh","login":"rkh","avatar_url":"https://secure.gravatar.com/avatar/5c2b452f6eea4a6d84c105ebd971d2a4?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":30442},"id":384475},{"created_at":"2010-09-02T05:35:17Z","body":"Scss
34
+ support was added after 1.0.1: http://github.com/rtomayko/tilt/commit/d6e8795c619970d0cfdbf4aead0869c592c44fe6","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/384487","updated_at":"2010-09-02T05:35:17Z","user":{"gravatar_id":"7fe945668a4fc098e886e20dea71d2ee","url":"https://api.github.com/users/zzak","login":"zzak","avatar_url":"https://secure.gravatar.com/avatar/7fe945668a4fc098e886e20dea71d2ee?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":277819},"id":384487},{"created_at":"2010-09-07T05:35:18Z","body":"You
35
+ can now do `rake spec` on 1.9.2p0, too. (And it passes, of course.)","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/392094","updated_at":"2010-09-07T05:35:39Z","user":{"gravatar_id":"5c2b452f6eea4a6d84c105ebd971d2a4","url":"https://api.github.com/users/rkh","login":"rkh","avatar_url":"https://secure.gravatar.com/avatar/5c2b452f6eea4a6d84c105ebd971d2a4?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":30442},"id":392094},{"created_at":"2010-09-19T21:21:50Z","body":"How
36
+ do you feel about including #62 and #63, maybe even #58?","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/416490","updated_at":"2010-09-19T21:21:50Z","user":{"gravatar_id":"5c2b452f6eea4a6d84c105ebd971d2a4","url":"https://api.github.com/users/rkh","login":"rkh","avatar_url":"https://secure.gravatar.com/avatar/5c2b452f6eea4a6d84c105ebd971d2a4?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","id":30442},"id":416490}]'
@@ -0,0 +1,21 @@
1
+ ---
2
+ - !binary "c2VydmVy": !binary |-
3
+ bmdpbngvMS4wLjEz
4
+ !binary "ZGF0ZQ==": !binary |-
5
+ VHVlLCAxMCBBcHIgMjAxMiAxMTo1MzoyNyBHTVQ=
6
+ !binary "Y29udGVudC10eXBl": !binary |-
7
+ YXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOA==
8
+ !binary "dHJhbnNmZXItZW5jb2Rpbmc=": !binary |-
9
+ Y2h1bmtlZA==
10
+ !binary "Y29ubmVjdGlvbg==": !binary |-
11
+ a2VlcC1hbGl2ZQ==
12
+ !binary "c3RhdHVz": !binary |-
13
+ MjAwIE9L
14
+ !binary "eC1yYXRlbGltaXQtbGltaXQ=": !binary |-
15
+ NTAwMA==
16
+ !binary "ZXRhZw==": !binary |-
17
+ ImJhOWJlN2ViNTlmZjBkZDZhNWFhYTU3MzM0ODE5ZjI5Ig==
18
+ !binary "eC1yYXRlbGltaXQtcmVtYWluaW5n": !binary |-
19
+ NDk5Mg==
20
+ - ! '{"created_at":"2010-09-01T15:42:44Z","body":"This all looks good to me. Anyone
21
+ run the unit tests under 1.8.6, 1.8.7, 1.9.2?","url":"https://api.github.com/repos/sinatra/sinatra/issues/comments/383214","updated_at":"2010-09-01T15:42:44Z","user":{"gravatar_id":"abfc88b96ae18c85ba7aac3bded2ec5e","avatar_url":"https://secure.gravatar.com/avatar/abfc88b96ae18c85ba7aac3bded2ec5e?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/rtomayko","login":"rtomayko","id":404},"id":383214}'
@@ -0,0 +1,23 @@
1
+ ---
2
+ - !binary "c2VydmVy": !binary |-
3
+ bmdpbngvMS4wLjEz
4
+ !binary "ZGF0ZQ==": !binary |-
5
+ VHVlLCAxMCBBcHIgMjAxMiAxMTo1MzoxMSBHTVQ=
6
+ !binary "Y29udGVudC10eXBl": !binary |-
7
+ YXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOA==
8
+ !binary "dHJhbnNmZXItZW5jb2Rpbmc=": !binary |-
9
+ Y2h1bmtlZA==
10
+ !binary "Y29ubmVjdGlvbg==": !binary |-
11
+ a2VlcC1hbGl2ZQ==
12
+ !binary "c3RhdHVz": !binary |-
13
+ MjAwIE9L
14
+ !binary "eC1yYXRlbGltaXQtbGltaXQ=": !binary |-
15
+ NTAwMA==
16
+ !binary "ZXRhZw==": !binary |-
17
+ Ijg2ODgwMDdjMWIwMWZiZmM3OTY2NGE1OWJiMjc2MjVlIg==
18
+ !binary "eC1yYXRlbGltaXQtcmVtYWluaW5n": !binary |-
19
+ NDk5NA==
20
+ - ! '{"merged":true,"created_at":"2010-09-01T11:33:50Z","review_comments":0,"number":56,"additions":2956,"head":{"repo":{"has_wiki":false,"created_at":"2009-12-03T10:42:35Z","description":"Classy
21
+ web-development dressed in a DSL","open_issues":0,"git_url":"git://github.com/rkh/sinatra.git","watchers":10,"pushed_at":"2012-03-22T10:06:05Z","url":"https://api.github.com/repos/rkh/sinatra","mirror_url":null,"fork":true,"html_url":"https://github.com/rkh/sinatra","homepage":"http://sinatra.github.com","svn_url":"https://github.com/rkh/sinatra","has_downloads":false,"size":160,"private":false,"updated_at":"2012-03-22T10:06:06Z","master_branch":"master","has_issues":false,"owner":{"gravatar_id":"5c2b452f6eea4a6d84c105ebd971d2a4","avatar_url":"https://secure.gravatar.com/avatar/5c2b452f6eea4a6d84c105ebd971d2a4?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/rkh","login":"rkh","id":30442},"name":"sinatra","forks":3,"language":"Ruby","clone_url":"https://github.com/rkh/sinatra.git","ssh_url":"git@github.com:rkh/sinatra.git","id":393951},"ref":"1.1","sha":"69791f71285c84e217efc061eee15ef32ffca515","label":"rkh:1.1","user":{"gravatar_id":"5c2b452f6eea4a6d84c105ebd971d2a4","avatar_url":"https://secure.gravatar.com/avatar/5c2b452f6eea4a6d84c105ebd971d2a4?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/rkh","login":"rkh","id":30442}},"merged_at":"2010-09-25T19:43:05Z","body":"Patches
22
+ prepared for 1.1 release. See also http://github.com/sinatra/sinatra/issues/issue/55","diff_url":"https://github.com/sinatra/sinatra/pull/56.diff","commits":81,"url":"https://api.github.com/repos/sinatra/sinatra/pulls/56","deletions":1065,"html_url":"https://github.com/sinatra/sinatra/pull/56","patch_url":"https://github.com/sinatra/sinatra/pull/56.patch","comments":10,"base":{"repo":{"has_wiki":false,"created_at":"2009-01-14T01:27:30Z","description":"Classy
23
+ web-development dressed in a DSL (official / canonical repo)","open_issues":12,"git_url":"git://github.com/sinatra/sinatra.git","watchers":3442,"pushed_at":"2012-04-02T13:58:27Z","url":"https://api.github.com/repos/sinatra/sinatra","mirror_url":null,"fork":true,"html_url":"https://github.com/sinatra/sinatra","homepage":"http://www.sinatrarb.com/","svn_url":"https://github.com/sinatra/sinatra","has_downloads":true,"size":460,"private":false,"updated_at":"2012-04-10T10:05:43Z","has_issues":true,"owner":{"gravatar_id":"22be51f9cf3849462ffc4107675ec182","avatar_url":"https://secure.gravatar.com/avatar/22be51f9cf3849462ffc4107675ec182?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-orgs.png","url":"https://api.github.com/users/sinatra","login":"sinatra","id":8312},"name":"sinatra","forks":431,"language":"Ruby","clone_url":"https://github.com/sinatra/sinatra.git","ssh_url":"git@github.com:sinatra/sinatra.git","id":106995},"ref":"master","sha":"1187a866346e82c98b8ad545b8f155632f7d9283","label":"sinatra:master","user":{"gravatar_id":"22be51f9cf3849462ffc4107675ec182","avatar_url":"https://secure.gravatar.com/avatar/22be51f9cf3849462ffc4107675ec182?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-orgs.png","url":"https://api.github.com/users/sinatra","login":"sinatra","id":8312}},"updated_at":"2010-09-25T19:43:06Z","state":"closed","mergeable":null,"_links":{"review_comments":{"href":"https://api.github.com/repos/sinatra/sinatra/pulls/56/comments"},"html":{"href":"https://github.com/sinatra/sinatra/pull/56"},"comments":{"href":"https://api.github.com/repos/sinatra/sinatra/issues/56/comments"},"self":{"href":"https://api.github.com/repos/sinatra/sinatra/pulls/56"}},"user":{"gravatar_id":"5c2b452f6eea4a6d84c105ebd971d2a4","avatar_url":"https://secure.gravatar.com/avatar/5c2b452f6eea4a6d84c105ebd971d2a4?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/rkh","login":"rkh","id":30442},"id":632,"merged_by":null,"changed_files":41,"closed_at":"2010-09-25T19:43:05Z","title":"1.1","issue_url":"https://github.com/sinatra/sinatra/issues/56"}'
@@ -0,0 +1,21 @@
1
+ ---
2
+ - !binary "c2VydmVy": !binary |-
3
+ bmdpbngvMS4wLjEz
4
+ !binary "ZGF0ZQ==": !binary |-
5
+ VHVlLCAxMCBBcHIgMjAxMiAxMjowODo1MSBHTVQ=
6
+ !binary "Y29udGVudC10eXBl": !binary |-
7
+ YXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOA==
8
+ !binary "dHJhbnNmZXItZW5jb2Rpbmc=": !binary |-
9
+ Y2h1bmtlZA==
10
+ !binary "Y29ubmVjdGlvbg==": !binary |-
11
+ a2VlcC1hbGl2ZQ==
12
+ !binary "c3RhdHVz": !binary |-
13
+ MjAwIE9L
14
+ !binary "eC1yYXRlbGltaXQtbGltaXQ=": !binary |-
15
+ NTAwMA==
16
+ !binary "ZXRhZw==": !binary |-
17
+ ImE2NGMxMmQ5Y2YyZTJmM2E5ZDgyNWMxNjJkNTc0ZjE2Ig==
18
+ !binary "eC1yYXRlbGltaXQtcmVtYWluaW5n": !binary |-
19
+ NDk4Nw==
20
+ - ! '{"created_at":"2008-02-19T03:30:53Z","type":"User","blog":"http://twitter.com/rtomayko","email":"r@tomayko.com","gravatar_id":"abfc88b96ae18c85ba7aac3bded2ec5e","followers":1099,"following":97,"url":"https://api.github.com/users/rtomayko","login":"rtomayko","public_repos":39,"hireable":false,"avatar_url":"https://secure.gravatar.com/avatar/abfc88b96ae18c85ba7aac3bded2ec5e?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","public_gists":84,"name":"Ryan
21
+ Tomayko","location":"San Francisco","bio":null,"html_url":"https://github.com/rtomayko","company":"GitHub","id":404}'
@@ -1,5 +1,15 @@
1
+ # encoding: utf-8
1
2
  require 'spec_helper'
2
3
 
3
4
  describe GH::Response do
4
- it 'is specified'
5
+ it 'handles UTF-8 properly, even if encoded binary' do
6
+ raw = '{"foo":"über cool sista året"}'
7
+ raw.force_encoding 'binary' if raw.respond_to? :force_encoding
8
+ response = GH::Response.new({}, raw)
9
+ response['foo'].should be == 'über cool sista året'
10
+ end
11
+
12
+ it 'handles broken encodings properly' do
13
+ GH::Response.new({}, "{\"foo\":\"\xC3\"}")["foo"].should be == "\xC3"
14
+ end
5
15
  end
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.1.2
4
+ version: 0.2.0
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-04-06 00:00:00.000000000 Z
12
+ date: 2012-04-10 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70120007137640 !ruby/object:Gem::Requirement
16
+ requirement: &70274565390500 !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: *70120007137640
24
+ version_requirements: *70274565390500
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: webmock
27
- requirement: &70120007137220 !ruby/object:Gem::Requirement
27
+ requirement: &70274565390060 !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: *70120007137220
35
+ version_requirements: *70274565390060
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: faraday
38
- requirement: &70120007136720 !ruby/object:Gem::Requirement
38
+ requirement: &70274565389500 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0.7'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70120007136720
46
+ version_requirements: *70274565389500
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: backports
49
- requirement: &70120007136220 !ruby/object:Gem::Requirement
49
+ requirement: &70274565388980 !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: *70120007136220
57
+ version_requirements: *70274565388980
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: multi_json
60
- requirement: &70120007135740 !ruby/object:Gem::Requirement
60
+ requirement: &70274565388440 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '1.0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70120007135740
68
+ version_requirements: *70274565388440
69
69
  description: multi-layer client for the github api v3
70
70
  email:
71
71
  - konstantin.mailinglists@googlemail.com
@@ -84,6 +84,7 @@ files:
84
84
  - lib/gh/case.rb
85
85
  - lib/gh/faraday.rb
86
86
  - lib/gh/lazy_loader.rb
87
+ - lib/gh/link_follower.rb
87
88
  - lib/gh/normalizer.rb
88
89
  - lib/gh/remote.rb
89
90
  - lib/gh/response.rb
@@ -93,8 +94,13 @@ files:
93
94
  - spec/cache_spec.rb
94
95
  - spec/gh_spec.rb
95
96
  - spec/lazy_loader_spec.rb
97
+ - spec/link_follower_spec.rb
96
98
  - spec/normalizer_spec.rb
99
+ - spec/payloads/repos/sinatra/sinatra/issues/56/comments.yml
100
+ - spec/payloads/repos/sinatra/sinatra/issues/comments/383214.yml
101
+ - spec/payloads/repos/sinatra/sinatra/pulls/56.yml
97
102
  - spec/payloads/users/rkh.yml
103
+ - spec/payloads/users/rtomayko.yml
98
104
  - spec/payloads/users/svenfuchs.yml
99
105
  - spec/remote_spec.rb
100
106
  - spec/response_spec.rb
@@ -121,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
127
  version: '0'
122
128
  requirements: []
123
129
  rubyforge_project:
124
- rubygems_version: 1.8.11
130
+ rubygems_version: 1.8.10
125
131
  signing_key:
126
132
  specification_version: 3
127
133
  summary: layered github client
@@ -129,8 +135,13 @@ test_files:
129
135
  - spec/cache_spec.rb
130
136
  - spec/gh_spec.rb
131
137
  - spec/lazy_loader_spec.rb
138
+ - spec/link_follower_spec.rb
132
139
  - spec/normalizer_spec.rb
140
+ - spec/payloads/repos/sinatra/sinatra/issues/56/comments.yml
141
+ - spec/payloads/repos/sinatra/sinatra/issues/comments/383214.yml
142
+ - spec/payloads/repos/sinatra/sinatra/pulls/56.yml
133
143
  - spec/payloads/users/rkh.yml
144
+ - spec/payloads/users/rtomayko.yml
134
145
  - spec/payloads/users/svenfuchs.yml
135
146
  - spec/remote_spec.rb
136
147
  - spec/response_spec.rb