ghee 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ class Ghee
2
+
3
+ # API module encapsulates all of API endpoints
4
+ # implemented thus far
5
+ #
6
+ module API
7
+
8
+ # The Users module handles all of the Github User
9
+ # API endpoints
10
+ #
11
+ module Users
12
+
13
+ # Users::Proxy inherits from Ghee::Proxy and
14
+ # enables defining methods on the proxy object
15
+ #
16
+ class Proxy < ::Ghee::ResourceProxy
17
+ include Ghee::CUD
18
+
19
+ # Gists for a user
20
+ #
21
+ # Returns json
22
+ #
23
+ def gists(params={})
24
+ Ghee::API::Gists::Proxy.new(connection,"#{path_prefix}/gists",params)
25
+ end
26
+
27
+ # Repos for a user
28
+ #
29
+ # Returns json
30
+ #
31
+ def repos(name=nil, params={})
32
+ params = name if name.is_a?Hash
33
+ prefix = name.is_a?(String) ? "/repos/#{self["login"]}/#{name}" : "#{path_prefix}/repos"
34
+ Ghee::API::Repos::Proxy.new(connection,prefix, params)
35
+ end
36
+
37
+ # Returns list of the provided users organizations or
38
+ # an organization by name
39
+ #
40
+ # org - String name of the organization (optional)
41
+ #
42
+ # Returns json
43
+ #
44
+ def orgs(org=nil, params={})
45
+ params = org if org.is_a?Hash
46
+ prefix = org.is_a?(String) ? "/orgs/#{org}" : "#{path_prefix}/orgs"
47
+ Ghee::API::Orgs::Proxy.new(connection, prefix, params)
48
+ end
49
+
50
+
51
+ end
52
+
53
+ # Get authenticated user
54
+ #
55
+ # Returns json
56
+ #
57
+ def user
58
+ Proxy.new(connection, '/user')
59
+ end
60
+
61
+ # Get a single user
62
+ #
63
+ # user - String of user login
64
+ #
65
+ # Returns json
66
+ #
67
+ def users(user)
68
+ Proxy.new(connection, "/users/#{user}")
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,33 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'multi_json'
4
+
5
+ class Ghee
6
+ class Connection < Faraday::Connection
7
+ attr_reader :hash
8
+
9
+ # Instantiates connection, accepts an options hash
10
+ # for authenticated access
11
+ #
12
+ # OAuth2 expects
13
+ # :access_token => "OAuth Token"
14
+ #
15
+ # Basic auth expects
16
+ # :basic_auth => {:user_name => "octocat", :password => "secret"}
17
+ def initialize(hash={})
18
+ @hash = hash
19
+ access_token = hash[:access_token] if hash.has_key?:access_token
20
+ basic_auth = hash[:basic_auth] if hash.has_key?:basic_auth
21
+
22
+ super('https://api.github.com') do |builder|
23
+ builder.use Faraday::Request::JSON
24
+ builder.use Faraday::Response::ParseJson
25
+ builder.adapter Faraday.default_adapter
26
+ end
27
+
28
+ self.headers["Authorization"] = "token #{access_token}" if access_token
29
+ self.basic_auth(basic_auth[:user_name], basic_auth[:password]) if basic_auth
30
+ self.headers["Accept"] = 'application/json'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,111 @@
1
+ class Ghee
2
+
3
+ # ResourceProxy lets us create a virtual
4
+ # proxy for any API resource, utilizing
5
+ # method_missing to handle passing
6
+ # messages to the real object
7
+ #
8
+ class ResourceProxy
9
+
10
+ # Undefine methods that might get in the way
11
+ instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval|instance_variable_get|object_id/ }
12
+
13
+ # Make connection and path_prefix readable
14
+ attr_reader :connection, :path_prefix, :params
15
+
16
+ # Expose pagination data
17
+ attr_reader :current_page, :total, :pagination
18
+
19
+ # Instantiates proxy with the connection
20
+ # and path_prefix
21
+ #
22
+ # connection - Ghee::Connection object
23
+ # path_prefix - String
24
+ #
25
+ def initialize(connection, path_prefix, params = {})
26
+ @connection, @path_prefix, @params = connection, path_prefix, params
27
+ end
28
+
29
+ # Method_missing takes any message passed
30
+ # to the ResourceProxy and sends it to the
31
+ # real object
32
+ #
33
+ # message - Message object
34
+ # args* - Arguements passed
35
+ #
36
+ def method_missing(message, *args, &block)
37
+ subject.send(message, *args, &block)
38
+ end
39
+
40
+ # Subject is the response body parsed
41
+ # as json
42
+ #
43
+ # Returns json
44
+ #
45
+ def subject
46
+ @subject ||= connection.get(path_prefix){|req| req.params.merge!params }.body
47
+ end
48
+
49
+ # Paginate is a helper method to handle
50
+ # request pagination to the github api
51
+ #
52
+ # options - Hash containing pagination params
53
+ # eg;
54
+ # :per_page => 100, :page => 1
55
+ #
56
+ # Returns self
57
+ #
58
+ def paginate(options)
59
+ @current_page = options.fetch(:page) {raise ArgumentError, ":page parameter required"}
60
+ per_page = options.delete(:per_page) || 30
61
+ response = connection.get do |req|
62
+ req.url path_prefix, :per_page => per_page, :page => current_page
63
+ req.params.merge! params
64
+ end
65
+
66
+ if @subject.nil?
67
+ @subject = response.body
68
+ else
69
+ @subject = @subject.concat response.body
70
+ end
71
+
72
+ parse_link_header response.headers.delete("link")
73
+
74
+ return self
75
+ end
76
+
77
+ def all
78
+ return self if pagination && next_page.nil?
79
+
80
+ self.paginate :per_page => 100, :page => next_page || 1
81
+
82
+ self.all
83
+ end
84
+
85
+ # Generate first_page, last_page, next_page, prev_page convienence methods
86
+ %w{ next prev first last }.each do |term|
87
+ define_method "#{term}_page" do
88
+ pagination ? pagination[term.to_sym] ? pagination[term.to_sym][:page] : nil : nil
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def parse_link_header(header)
95
+ return @total = subject.size, @pagination = {} if header.nil?
96
+ require 'cgi'
97
+ pattern = /<(?<link>.*)>;\s+rel="(?<rel>.*)"/
98
+ matches = {}
99
+ header.split(',').each do |m|
100
+ match = pattern.match m
101
+ uri = URI.parse(match[:link])
102
+ uri_params = CGI.parse(uri.query)
103
+ page = uri_params["page"].first.to_i
104
+ per_page = uri_params["per_page"] ? uri_params["per_page"].first.to_i : 30
105
+ matches[match[:rel].to_sym] = {:link => match[:link], :page => page, :per_page => per_page}
106
+ end
107
+ @pagination = matches
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,29 @@
1
+ class Ghee
2
+ module CUD
3
+
4
+ # Creates
5
+ #
6
+ # return json
7
+ #
8
+ def create(attributes)
9
+ connection.post(path_prefix,attributes).body
10
+ end
11
+
12
+ # Patchs
13
+ #
14
+ # return json
15
+ #
16
+ def patch(attributes)
17
+ connection.patch(path_prefix, attributes).body
18
+ end
19
+
20
+ # Destroys
21
+ #
22
+ # return boolean
23
+ #
24
+ def destroy
25
+ connection.delete(path_prefix).status == 204
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ class Ghee
3
+ VERSION = "0.7.0"
4
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ghee::API::Authorizations do
4
+ subject { Ghee.new(GH_AUTH) }
5
+
6
+ describe "#authorizations" do
7
+
8
+ context "with a test authorization" do
9
+ before :all do
10
+ VCR.use_cassette "authorizations.create.test" do
11
+ @test_auth = subject.authorizations.create :scopes => ["public_repo"]
12
+ @test_auth.should_not be_nil
13
+ end
14
+ end
15
+
16
+ let(:test_auth) {@test_auth}
17
+
18
+ it "should return an auth" do
19
+ VCR.use_cassette "authorizations(id)" do
20
+ auth = subject.authorizations(test_auth["id"])
21
+ auth["scopes"].should include("public_repo")
22
+ end
23
+ end
24
+
25
+ it "should return a list of auths" do
26
+ VCR.use_cassette "authorizations" do
27
+ auth = subject.authorizations
28
+ auth.size().should > 0
29
+ end
30
+ end
31
+
32
+ it "should patch an auth" do
33
+ VCR.use_cassette "authorization(id).patch" do
34
+ auth = subject.authorizations(test_auth["id"]).patch :add_scopes => ["repo"]
35
+ auth["scopes"].should include("repo")
36
+ end
37
+ end
38
+
39
+ after :all do
40
+ VCR.use_cassette "authorizations(id).destroy" do
41
+ subject.authorizations(test_auth["id"]).destroy.should be_true
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ghee::API::Events do
4
+ subject { Ghee.new(GH_AUTH) }
5
+
6
+ EventTypes = ["CommitComment","CreateEvent","DeleteEvent","DownloadEvent","FollowEvent",
7
+ "ForkEvent","ForkApplyEvent","GistEvent","GollumEvent","IssueCommentEvent",
8
+ "IssuesEvent","MemberEvent","PublicEvent","PullRequestEvent","PushEvent",
9
+ "TeamAddEvent","WatchEvent"]
10
+
11
+ def should_be_an_event(event)
12
+ EventTypes.should include(event['type'])
13
+ event['repo'].should be_instance_of(Hash)
14
+ event['actor'].should be_instance_of(Hash)
15
+ event['org'].should be_instance_of(Hash)
16
+ event['created_at'].should_not be_nil
17
+ end
18
+
19
+ describe "#events" do
20
+ it "should return public events" do
21
+ VCR.use_cassette('events') do
22
+ events = subject.events
23
+ events.size.should > 0
24
+ should_be_an_event(events.first)
25
+ end
26
+ end
27
+ describe "#paginate" do
28
+ it "should return page 1" do
29
+ VCR.use_cassette "events.page1" do
30
+ events = subject.events.paginate :page => 1
31
+ events.size.should > 0
32
+ events.next_page.should == 2
33
+ should_be_an_event(events.first)
34
+ end
35
+ end
36
+ it "should return page 2" do
37
+ VCR.use_cassette "events.page2" do
38
+ events = subject.events.paginate :page => 2
39
+ events.size.should > 0
40
+ events.next_page.should == 3
41
+ events.prev_page.should == 1
42
+ should_be_an_event(events.first)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,153 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ghee::API::Gists do
4
+ subject { Ghee.new(GH_AUTH) }
5
+
6
+ def should_be_a_gist(gist)
7
+ gist['url'].should include('https://api.github.com/gists/')
8
+ gist['user']['url'].should include('https://api.github.com/users/')
9
+ gist['created_at'].should_not be_nil
10
+ gist['files'].should be_instance_of(Hash)
11
+ gist['files'].size.should > 0
12
+ end
13
+
14
+ describe "#users" do
15
+ describe "#gists" do
16
+ it "should return users gists" do
17
+ VCR.use_cassette('users(login).gists') do
18
+ gists = subject.users('jonmagic').gists
19
+ gists.size.should > 0
20
+ should_be_a_gist(gists.first)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ describe "#gists" do
27
+ it "should return gists for authenticated user" do
28
+ VCR.use_cassette('gists') do
29
+ gists = subject.gists
30
+ gists.size.should > 0
31
+ should_be_a_gist(gists.first)
32
+ end
33
+ end
34
+
35
+ describe "#public" do
36
+ it "should return public gists" do
37
+ VCR.use_cassette('gists.public') do
38
+ gists = subject.gists.public
39
+ gists.size.should > 0
40
+ should_be_a_gist(gists.first)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "#starred" do
46
+ it "should return starred gists" do
47
+ VCR.use_cassette('gists.starred') do
48
+ gists = subject.gists.starred
49
+ gists.size.should > 0
50
+ should_be_a_gist(gists.first)
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "#create" do
56
+ it "should create a gist" do
57
+ VCR.use_cassette('gists.create') do
58
+ gist = subject.gists.create({
59
+ :description => "Testing the ghee api",
60
+ :public => true,
61
+ :files => {
62
+ 'ghee_test.txt' => {
63
+ :content => "Booya!"
64
+ }
65
+ }
66
+ })
67
+ should_be_a_gist(gist)
68
+ subject.gists(gist['id']).destroy
69
+ end
70
+ end
71
+ end
72
+
73
+ context "with gist id" do
74
+ before(:all) do
75
+ VCR.use_cassette('gists.test') do
76
+ @test_gist = subject.gists.create({:public => false, :files => {'file.txt' => {:content => 'ready to destroy'}}})
77
+ end
78
+ end
79
+ let(:test_gist) { @test_gist }
80
+
81
+ it "should return single gist" do
82
+ VCR.use_cassette('gists(id)') do
83
+ gist = subject.gists(test_gist['id'])
84
+ gist['id'].should == test_gist['id']
85
+ should_be_a_gist(gist)
86
+ end
87
+ end
88
+
89
+ describe "#patch" do
90
+ it "should patch the gist" do
91
+ VCR.use_cassette('gists(id).patch') do
92
+ gist = subject.gists(test_gist['id']).patch({
93
+ :files => {
94
+ 'test.md' => {
95
+ :content => 'clarified butter'
96
+ }
97
+ }
98
+ })
99
+ should_be_a_gist(gist)
100
+ gist['files']['test.md']['content'].should == 'clarified butter'
101
+ end
102
+ end
103
+ end
104
+
105
+ describe "#star" do
106
+ it "should star the gist" do
107
+ VCR.use_cassette('gists(id).star') do
108
+ subject.gists(test_gist['id']).star.should be_true
109
+ end
110
+ end
111
+ end
112
+
113
+ describe "#unstar" do
114
+ it "should star the gist" do
115
+ VCR.use_cassette('gists(id).unstar') do
116
+ subject.gists(test_gist['id']).unstar.should be_true
117
+ end
118
+ end
119
+ end
120
+
121
+ describe "#starred?" do
122
+ it "should return true if gist is starred" do
123
+ VCR.use_cassette('gists(id).starred? is true') do
124
+ subject.gists(test_gist['id']).star
125
+ subject.gists(test_gist['id']).starred?.should be_true
126
+ end
127
+ end
128
+
129
+ it "should return false if gist is unstarred" do
130
+ VCR.use_cassette('gists(id).starred? is false') do
131
+ subject.gists(test_gist['id']).unstar
132
+ subject.gists(test_gist['id']).starred?.should be_false
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "#destroy" do
138
+ it "should delete the gist and return true" do
139
+ VCR.use_cassette('gists(id).destroy true') do
140
+ gist = subject.gists.create({:public => false, :files => {'file.txt' => {:content => 'ready to destroy'}}})
141
+ subject.gists(gist['id']).destroy.should be_true
142
+ end
143
+ end
144
+
145
+ it "should return false if gist doesn't exist" do
146
+ VCR.use_cassette('gists(id).destroy false') do
147
+ subject.gists("12345678901234567890").destroy.should be_false
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end