git_hub 0.0.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/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == git_hub 0.0.1 / 2010-01-05
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/README.txt ADDED
@@ -0,0 +1,61 @@
1
+ = git_hub
2
+ by:: Arvicco
3
+ url:: http://github.com/arvicco/git_hub
4
+
5
+ == DESCRIPTION:
6
+
7
+ git_hub is a library that wraps github API and exposes simple interface for
8
+ finding, creating and managing github repositories and other resources.
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ * FIXME (list of features or problems)
13
+ This project is quite new, so it's probably not ready for prime time just yet...
14
+ Contributors always welcome!
15
+
16
+ == SYNOPSIS:
17
+
18
+ require 'git_hub'
19
+ include GitHub
20
+
21
+ # Find existing repos
22
+ repo = Repo.find(:user=>user_name, :repo=>repo_name)
23
+ repos = Repo.find(:user=>user_name)
24
+ search_repos = Repo.find(:query=>['search','terms'])
25
+
26
+ # Create new repo (need to authenticate with your github credentials first)
27
+ Api.auth = {:user=>user_name, :token=>token}
28
+ new_repo = Repo.create(:name=>repo_name, :desc=>'Description', :homepage=>'http://your_page.org', :private=> false)
29
+
30
+ == REQUIREMENTS:
31
+
32
+ * FIXME (list of requirements)
33
+
34
+ == INSTALL:
35
+
36
+ $ sudo gem install git_hub
37
+
38
+ == LICENSE:
39
+
40
+ (The MIT License)
41
+
42
+ Copyright (c) 2009 Arvicco
43
+
44
+ Permission is hereby granted, free of charge, to any person obtaining
45
+ a copy of this software and associated documentation files (the
46
+ 'Software'), to deal in the Software without restriction, including
47
+ without limitation the rights to use, copy, modify, merge, publish,
48
+ distribute, sublicense, and/or sell copies of the Software, and to
49
+ permit persons to whom the Software is furnished to do so, subject to
50
+ the following conditions:
51
+
52
+ The above copyright notice and this permission notice shall be
53
+ included in all copies or substantial portions of the Software.
54
+
55
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
56
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
57
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
58
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
59
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
60
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
61
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+
2
+ require 'bones' rescue abort '### Please install the "bones" gem ###'
3
+
4
+ ensure_in_path 'lib'
5
+ require 'git_hub'
6
+
7
+ task :default => 'test:run'
8
+ task 'gem:release' => 'test:run'
9
+
10
+ Bones {
11
+ ignore_file '.gitignore'
12
+ name 'git_hub'
13
+ authors 'Arvicco'
14
+ email 'arvitallian@gmail.com'
15
+ url 'http://github.com/arvicco/git_hub'
16
+ version GitHub::VERSION
17
+ ignore_file '.gitignore'
18
+ }
19
+
20
+ # EOF
data/bin/git_hub ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib git_hub]))
5
+
6
+ # Put your code here
7
+
@@ -0,0 +1,39 @@
1
+ require 'net/https'
2
+ require 'singleton'
3
+
4
+ module GitHub
5
+ class Api
6
+ include Singleton
7
+
8
+ attr_writer :auth
9
+
10
+ def auth
11
+ @auth || {}
12
+ end
13
+
14
+ def authenticated?
15
+ auth != {}
16
+ end
17
+
18
+ # Turns string into appropriate class constant, returns nil if class not found
19
+ def classify name
20
+ klass = name.split("::").inject(Kernel) {|klass, const_name| klass.const_get const_name }
21
+ klass.is_a?(Class) ? klass : nil
22
+ rescue NameError
23
+ nil
24
+ end
25
+
26
+ def request verb, url, params = {}
27
+ method = classify('Net::HTTP::' + verb.to_s.capitalize)
28
+ uri = URI.parse url
29
+ server = Net::HTTP.new(uri.host, uri.port)
30
+ server.use_ssl = (uri.scheme == 'https')
31
+ server.verify_mode = OpenSSL::SSL::VERIFY_NONE if server.use_ssl?
32
+ server.start do |http|
33
+ req = method.new(uri.path)
34
+ req.form_data = params.merge(auth)
35
+ http.request(req)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,50 @@
1
+ require 'yaml'
2
+
3
+ module GitHub
4
+ class Base
5
+ @base_uri = ''
6
+
7
+ def initialize(attributes={})
8
+ attributes.each do |key, value|
9
+ raise "No attr_accessor for #{key} on #{self.class}" unless respond_to?("#{key}=")
10
+ self.send("#{key}=", value)
11
+ end
12
+ end
13
+
14
+ def self.base_uri uri
15
+ @base_uri = uri
16
+ end
17
+
18
+ class << self
19
+ def request verb, uri, params = {}
20
+ res = api.request verb, @base_uri+uri, params
21
+ YAML::load(res.body) if res.respond_to?(:body) # res.kind_of?(Net::HTTPSuccess)
22
+ #p "in show: #{res}: #{res.code}: #{res.http_version}: #{res.message}", res.body
23
+ end
24
+
25
+ def get uri, params ={}
26
+ request :get, uri, params
27
+ end
28
+
29
+ def post uri, params = {}
30
+ request :post, uri, params
31
+ end
32
+
33
+ def api
34
+ @@api ||= GitHub::Api.instance
35
+ end
36
+ end
37
+
38
+ def get uri, params ={}
39
+ self.class.get uri, params
40
+ end
41
+
42
+ def post uri, params ={}
43
+ self.class.post uri, params
44
+ end
45
+
46
+ def api
47
+ self.class.api
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,155 @@
1
+ module GitHub
2
+ class Repo < Base
3
+ GITHUB_SERVICES = {
4
+ #[github]
5
+ # user = user
6
+ # token = token
7
+ # :donate => {:path => '/edit/donate', :inputs => ['paypal']}
8
+ # homepage = homepage_url
9
+ # webhooks => {:path => '/edit/postreceive_urls', :fields => []
10
+ #http://rdoc.info/projects/update, http://runcoderun.com/github, http://api.devver.net/github
11
+ # basecamp = url, username, password, project, category
12
+ # cia = true
13
+ # campfire = subdomain, username, password, room, ssl, play_sound
14
+ # email = arvitallian@gmail.com
15
+ # fogbugz = cvssubmit_url, fb_version, fb_repoid
16
+ # friendfeed = nickname, remotekey
17
+ # irc = server, port, room, password, nick, ssl
18
+ # jabber = user
19
+ # lighthouse = subdomain, project_id, token, private
20
+ # presently = subdomain, group_name, username, password
21
+ # rubyforge = username, password, grupid
22
+ # runcoderun = true
23
+ # trac = url, token
24
+ # twitter = username, password, digest
25
+ }
26
+
27
+ base_uri 'http://github.com/api/v2/yaml/repos'
28
+
29
+ attr_accessor :name, :owner, :description, :url, :homepage, :open_issues, :watchers, :forks, :fork, :private,
30
+ # additional attributes from search:
31
+ :id, :type, :size, :language, :created, :pushed, :score #?
32
+
33
+ def initialize options
34
+ super
35
+ raise "Unable to initialize #{self.class} without name" unless @name
36
+ @url ||= "http://github.com/#{@owner}/#{@name}"
37
+ @type ||= "repo"
38
+ end
39
+
40
+ alias followers= watchers=
41
+ alias followers watchers
42
+ alias username= owner=
43
+ alias username owner
44
+
45
+ def fork?;
46
+ !!self.fork
47
+ end
48
+
49
+ def private?;
50
+ !!self.private
51
+ end
52
+
53
+ def clone_url
54
+ url = private? || api.auth['login'] == self.owner ? "git@github.com:" : "git://github.com/"
55
+ url += "#{self.owner}/#{self.name}.git"
56
+ end
57
+
58
+ class << self # Repo class methods
59
+ # Find repo(s) of a (valid) github user
60
+ # Accepts either options Hash (:owner/:user/:username and :repo/:repository/:project/:name)
61
+ # or several search terms as strings or symbols
62
+ def find(*params)
63
+ if params.size == 1 && params.first.is_a?(Hash) # this is /show request
64
+ opts = params.first
65
+ owner = opts[:owner] || opts[:user] || opts[:username] || opts[:login] || api.auth['login'] || ''
66
+ repo = opts[:repo] || opts[:repository] || opts[:name] || opts[:project]
67
+ path = repo ? "/show/#{owner}/#{repo}" : "/show/#{owner}"
68
+ else # this is /search request, params are search terms
69
+ query = params.map(&:to_s).join('+')
70
+ path = "/search/#{query}"
71
+ end
72
+ result = get(path)
73
+ if result['repository']
74
+ new result['repository']
75
+ elsif result['repositories']
76
+ result['repositories'].map {|r| new r}
77
+ else
78
+ result
79
+ end
80
+ end
81
+
82
+ alias show find
83
+ alias search find
84
+
85
+ # Create new github repo, accepts Hash with :repo, :description, :homepage, :public/:private
86
+ # or repo name as a single parameter
87
+ def create(*params)
88
+ if params.size == 1 && params.first.is_a?(Hash)
89
+ opts = params.first
90
+ repo = opts[:repo] || opts[:repository] || opts[:name] || opts[:project]
91
+ description = opts[:description] || opts[:descr] || opts[:desc]
92
+ homepage = opts[:homepage]
93
+ public = opts[:public] || !opts[:private] # default to true
94
+ else # repo name as a single parameter
95
+ repo = params.first.to_s
96
+ description = nil
97
+ homepage = nil
98
+ public = false
99
+ end
100
+ raise("Unable to create #{self.class} without authorization") unless api.authenticated?
101
+ result = post("/create", 'name' => repo, 'description' => description,
102
+ 'homepage' => homepage, 'public' => (public ? 1 : 0))
103
+ if result['repository']
104
+ new result['repository']
105
+ else
106
+ result
107
+ end
108
+ end
109
+ end
110
+
111
+ # Delete github repo
112
+ def delete
113
+ result = post("/delete/#{@name}")
114
+ if result['delete_token']
115
+ post("/delete/#{@name}", 'delete_token' => result['delete_token'])
116
+ else
117
+ result
118
+ end
119
+ end
120
+
121
+ def add_service
122
+ end
123
+
124
+ def remove_service
125
+ end
126
+
127
+ def add_collaborator
128
+ end
129
+
130
+ def remove_collaborator
131
+ end
132
+
133
+ # repos/show/:user/:repo/tags
134
+ # repos/show/:user/:repo/branches
135
+ # repos/show/:user/:repo/languages
136
+ # repos/show/:user/:repo/network
137
+ #
138
+ # repos/show/:user/:repo/collaborators
139
+ # POST repos/collaborators/:repo/add/:user
140
+ # POST repos/collaborators/:repo/remove/:user
141
+ #
142
+ # repos/keys/:repo
143
+ # POST repos/key/:repo/remove
144
+ # POST repos/key/:repo/add {title => title of the key, key => public key data}
145
+
146
+ # POST repos/set/public/:repo
147
+ # POST repos/set/private/:repo
148
+
149
+ # ? repos/fork/:user/:repo
150
+ # repos/unwatch/:user/:repo
151
+ # repos/watch/:user/:repo
152
+ # repos/show/:user/:repo ? new?
153
+
154
+ end
155
+ end
data/lib/git_hub.rb ADDED
@@ -0,0 +1,48 @@
1
+
2
+ module GitHub
3
+
4
+ # :stopdoc:
5
+ VERSION = '0.0.1'
6
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
7
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
8
+ # :startdoc:
9
+
10
+ # Returns the version string for the library.
11
+ #
12
+ def self.version
13
+ VERSION
14
+ end
15
+
16
+ # Returns the library path for the module. If any arguments are given,
17
+ # they will be joined to the end of the libray path using
18
+ # <tt>File.join</tt>.
19
+ #
20
+ def self.libpath( *args )
21
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
22
+ end
23
+
24
+ # Returns the path for the module. If any arguments are given,
25
+ # they will be joined to the end of the path using
26
+ # <tt>File.join</tt>.
27
+ #
28
+ def self.path( *args )
29
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
30
+ end
31
+
32
+ # Utility method used to require all files ending in .rb that lie in the
33
+ # directory below this file that has the same name as the filename passed
34
+ # in. Optionally, a specific _directory_ name can be passed in such that
35
+ # the _filename_ does not have to be equivalent to the directory.
36
+ #
37
+ def self.require_all_libs_relative_to( fname, dir = nil )
38
+ dir ||= ::File.basename(fname, '.*')
39
+ search_me = ::File.expand_path(
40
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
41
+
42
+ Dir.glob(search_me).sort.each {|rb| require rb}
43
+ end
44
+
45
+ end # module GitHub
46
+
47
+ GitHub.require_all_libs_relative_to(__FILE__)
48
+
@@ -0,0 +1,99 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), '..', 'spec_helper'))
3
+
4
+ module GitHubTest
5
+ describe GitHub::Api do
6
+ after(:each) do
7
+ GitHub::Api.instance.auth.clear
8
+ end
9
+
10
+ context 'authentication' do
11
+ it 'starts out unauthenticated' do
12
+ api = described_class.instance
13
+ api.should_not be_authenticated
14
+ api.auth.should == {}
15
+ end
16
+
17
+ it 'authenticates with login and token' do
18
+ api = described_class.instance
19
+ api.auth = joe_auth
20
+ api.should be_authenticated
21
+ api.auth.should == joe_auth
22
+ api.auth.clear
23
+ api.should_not be_authenticated
24
+ api.auth.should == {}
25
+ end
26
+ end
27
+
28
+ context 'requests' do
29
+ before :each do
30
+ @api= described_class.instance
31
+ @api.auth = joe_auth
32
+ @hash = {'name' => 'name', 'description' => 'descr'}
33
+ @hash_with_auth = @hash.merge joe_auth
34
+ end
35
+
36
+ context 'post' do
37
+ it 'connects via http, submits post request' do
38
+ server, post = stub_server_and_req()
39
+ Net::HTTP::Post.should_receive(:new).with('/api/v2/yaml/repos/create').and_return(post)
40
+ Net::HTTP.should_receive(:new).with('github.com', 80).and_return(server)
41
+ server.should_receive(:request).with(post)
42
+
43
+ @api.request(:post, "#{github_yaml}/repos/create", @hash)
44
+ end
45
+
46
+ it 'connects to github via https, submits post request' do
47
+ server, post = stub_server_and_req( :port => 443)
48
+ Net::HTTP::Post.should_receive(:new).with('/api/v2/yaml/repos/create').and_return(post)
49
+ Net::HTTP.should_receive(:new).with('github.com', 443).and_return(server)
50
+ server.should_receive(:request).with(post)
51
+
52
+ @api.request(:post, 'https://github.com/api/v2/yaml/repos/create', @hash)
53
+ end
54
+
55
+ it 'sends form params urlencoded with added authentication' do
56
+ server = stub_server
57
+ server.should_receive(:request) do |req|
58
+ req.content_type.should == 'application/x-www-form-urlencoded'
59
+ req.body.should == 'name=name&description=descr&login=joe007&token=b937c8e7ea5a5b47f94eafa39b1e0462'
60
+ end
61
+
62
+ @api.request(:post, "#{github_yaml}/repos/create", @hash)
63
+ end
64
+ end
65
+
66
+ context 'get' do
67
+ it 'connects to github via http, submits get request' do
68
+ server, req = stub_server_and_req(:get => true)
69
+ Net::HTTP::Get.should_receive(:new).with('/api/v2/yaml/repos/create').and_return(req)
70
+ Net::HTTP.should_receive(:new).with('github.com', 80).and_return(server)
71
+ server.should_receive(:request).with(req)
72
+
73
+ @api.request(:get, "#{github_yaml}/repos/create")
74
+ end
75
+
76
+ it 'connects to github via https, submits get request' do
77
+ server, req = stub_server_and_req(:get => true, :port => 443)
78
+ Net::HTTP::Get.should_receive(:new).with('/api/v2/yaml/repos/create').and_return(req)
79
+ Net::HTTP.should_receive(:new).with('github.com', 443).and_return(server)
80
+ server.should_receive(:request).with(req)
81
+
82
+ @api.request(:get, "https://github.com/api/v2/yaml/repos/create")
83
+ end
84
+
85
+ it 'sends get request with added authentication' do
86
+ server = stub_server(:get => true)
87
+ server.should_receive(:request) do |req|
88
+ req.content_type.should == 'application/x-www-form-urlencoded'
89
+ req.body.should == 'login=joe007&token=b937c8e7ea5a5b47f94eafa39b1e0462'
90
+ end
91
+
92
+ @api.request(:get, "#{github_yaml}/repos/create")
93
+ end
94
+ end # requests
95
+ end
96
+ end
97
+ end # module GitHubTest
98
+
99
+ # EOF
@@ -0,0 +1,47 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), '..', 'spec_helper'))
3
+
4
+ module GitHubTest
5
+ describe GitHub::Base do
6
+ after(:each) do
7
+ api.auth.clear
8
+ end
9
+
10
+ context 'general' do
11
+ it 'has instance and class method api pointing to the same Api instance' do
12
+ api1 = described_class.api
13
+ api2 = described_class.new.api
14
+ api1.should be_a GitHub::Api
15
+ api1.should be_equal api2
16
+ api1.should be_equal api
17
+ end
18
+ end
19
+
20
+ context 'requests' do
21
+ it 'submits appropriate requests to api as get/post methods (both class and instance)' do
22
+ base = described_class.new
23
+ api.should_receive(:request).with(:get, '/blah', anything()).twice
24
+ base.get ('/blah')
25
+ described_class.get ('/blah')
26
+
27
+ api.should_receive(:request).with(:post, '/blah', anything()).twice
28
+ base.post ('/blah')
29
+ described_class.post ('/blah')
30
+ end
31
+
32
+ it 'prepends get/post calls to api by string set by base_uri class macro' do
33
+ base = described_class.new
34
+ described_class.class_eval { base_uri 'http://base1.com' }
35
+ api.should_receive(:request).with(:get, 'http://base1.com/blah', anything()).twice
36
+ base.get ('/blah')
37
+ described_class.get ('/blah')
38
+
39
+ api.should_receive(:request).with(:post, 'http://base1.com/blah', anything()).twice
40
+ base.post ('/blah')
41
+ described_class.post ('/blah')
42
+ end
43
+ end
44
+ end
45
+ end # module GitHubTest
46
+
47
+ # EOF
@@ -0,0 +1,247 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), '..', 'spec_helper'))
3
+
4
+ module GitHubTest
5
+ describe GitHub::Repo do
6
+ after(:each) do
7
+ api.auth.clear
8
+ end
9
+
10
+ context '::find as /show/:user)' do
11
+ it 'returns an array of repos for a valid github user' do
12
+ expect(:get, "#{github_yaml}/repos/show/joe007") do
13
+ repos = described_class.find(:user=>'joe007')
14
+ repos.should_not be_empty
15
+ repos.should be_an Array
16
+ repos.should have(3).repos
17
+ repos.each {|repo| repo.should be_a described_class}
18
+ end
19
+ end
20
+
21
+ it 'returns repos with "show" attributes set' do
22
+ expect(:get, "#{github_yaml}/repos/show/joe007") do
23
+ repo = described_class.find(:user=>'joe007').first
24
+ repo.name.should == 'fine_repo'
25
+ repo.url.should == 'http://github.com/joe007/fine_repo'
26
+ repo.clone_url.should == 'git://github.com/joe007/fine_repo.git'
27
+ repo.description.should == 'Fine repo by joe'
28
+ repo.homepage.should == ''
29
+ repo.watchers.should == 3
30
+ repo.followers.should == 3
31
+ repo.open_issues.should == 0
32
+ repo.forks.should == 0
33
+ repo.should_not be_fork
34
+ repo.should_not be_private
35
+ repo.owner.should == 'joe007'
36
+ repo.username.should == 'joe007'
37
+ end
38
+ end
39
+
40
+ it 'returns repos with "search" attributes unset' do
41
+ expect(:get, "#{github_yaml}/repos/show/joe007") do
42
+ repo = described_class.find(:user=>'joe007').first
43
+ repo.id.should == nil
44
+ repo.language.should == nil
45
+ repo.size.should == nil
46
+ repo.created.should == nil
47
+ repo.pushed.should == nil
48
+ repo.score.should == nil
49
+ repo.type.should == 'repo'
50
+ end
51
+ end
52
+ end
53
+
54
+ context '::find as /search' do
55
+ it 'searches github repos with specific search terms' do
56
+ expect(:get, "#{github_yaml}/repos/search/joe+repo") do
57
+ repos = described_class.find('joe', 'repo')
58
+ repos.should_not be_empty
59
+ repos.should be_an Array
60
+ repos.should have(3).repos
61
+ repos.each {|repo| repo.should be_a described_class}
62
+ end
63
+ end
64
+
65
+ it 'returns repos with "search" attributes set' do
66
+ expect(:get, "#{github_yaml}/repos/search/joe+repo") do
67
+ repo = described_class.find('joe', 'repo').first
68
+ repo.name.should == 'fine_repo'
69
+ repo.description.should == 'Fine repo by joe'
70
+ repo.watchers.should == 3
71
+ repo.followers.should == 3
72
+ repo.forks.should == 0
73
+ repo.should_not be_fork
74
+ repo.owner.should == 'joe007'
75
+ repo.username.should == 'joe007'
76
+ repo.id.should == 'repo-270000'
77
+ repo.language.should == ''
78
+ repo.size.should == 1228
79
+ repo.created.should == '2009-08-06T00:20:39Z'
80
+ repo.pushed.should == '2009-11-11T22:58:52Z'
81
+ repo.score.should == 4.918499
82
+ repo.type.should == 'repo'
83
+ repo.clone_url.should == 'git://github.com/joe007/fine_repo.git'
84
+ end
85
+ end
86
+
87
+ it 'returns repos with "show" attributes unset' do
88
+ expect(:get, "#{github_yaml}/repos/search/joe+repo") do
89
+ repo = described_class.find('joe', 'repo').first
90
+ repo.url.should == 'http://github.com/joe007/fine_repo'
91
+ repo.homepage.should == nil
92
+ repo.open_issues.should == nil
93
+ repo.should_not be_private
94
+ end
95
+ end
96
+ end
97
+
98
+ context '::find as /show/user/repo' do
99
+ it 'finds repo of a (valid) github user' do
100
+ expect(:get, "#{github_yaml}/repos/show/joe007/fine_repo") do
101
+ repo = described_class.find(:user=>'joe007', :repo=>'fine_repo')
102
+ repo.should be_a described_class
103
+ repo.name.should == 'fine_repo'
104
+ repo.url.should == 'http://github.com/joe007/fine_repo'
105
+ repo.clone_url.should == 'git://github.com/joe007/fine_repo.git'
106
+ repo.description.should == 'Fine repo by joe'
107
+ repo.homepage.should == ''
108
+ repo.watchers.should == 1
109
+ repo.followers.should == 1
110
+ repo.open_issues.should == 0
111
+ repo.forks.should == 0
112
+ repo.should_not be_fork
113
+ repo.should_not be_private
114
+ repo.owner.should == 'joe007'
115
+ repo.username.should == 'joe007'
116
+ end
117
+ end
118
+
119
+ it 'returns error object instead of non-existing repo' do
120
+ expect(:get, "#{github_yaml}/repos/show/joe007/err_repo") do
121
+ res = described_class.find(:user=>'joe007', :repo=>'err_repo')
122
+ res.should have_key 'error' # res = {"error"=>[{"error"=>"repository not found"}]}
123
+ res['error'].should be_kind_of Array
124
+ res['error'].first.should have_key 'error'
125
+ end
126
+ end
127
+ end
128
+
129
+ context '::create' do
130
+ it 'creates new repo for authenticated github user' do
131
+ api.auth = joe_auth
132
+ keys = {:name => 'new_repo', :description => 'New repo',
133
+ :homepage => 'http://joe.org/new_repo', :public => 1}.merge joe_auth
134
+ expects(:post, "#{github_yaml}/repos/create", :expected_keys=>keys, :body=>body_from_file('/repos/create'))
135
+ repo = described_class.create(:name=>'new_repo', :description => 'New repo',
136
+ :homepage => 'http://joe.org/new_repo', :private => false)
137
+ repo.should be_a described_class
138
+ repo.name.should == 'new_repo'
139
+ repo.url.should == 'http://github.com/joe007/new_repo'
140
+ repo.clone_url.should == 'git@github.com:joe007/new_repo.git'
141
+ repo.description.should == 'New repo'
142
+ repo.homepage.should == 'http://joe.org/new_repo'
143
+ repo.watchers.should == 1
144
+ repo.followers.should == 1
145
+ repo.open_issues.should == 0
146
+ repo.forks.should == 0
147
+ repo.should_not be_fork
148
+ repo.should_not be_private
149
+ repo.owner.should == 'joe007'
150
+ repo.username.should == 'joe007'
151
+ end
152
+ end
153
+
154
+ context '#delete' do
155
+ it 'deletes new repo for authenticated github user' do
156
+ api.auth = joe_auth
157
+ expect(:get, "#{github_yaml}/repos/show/joe007/new_repo")
158
+ repo = described_class.find(:repo=>'new_repo')
159
+ post1 = { :expected_keys => joe_auth,
160
+ :body => body_from_file('/repos/delete/new_repo.1') }
161
+ post2 = { :expected_keys => {:delete_token => :any}.merge(joe_auth),
162
+ :body => body_from_file('/repos/delete/new_repo.2') }
163
+ expects(:post, "#{github_yaml}/repos/delete/new_repo", [post1, post2])
164
+ res = repo.delete
165
+ res['status'].should == 'deleted'
166
+ end
167
+ end
168
+
169
+ it 'tests' do
170
+ pending
171
+ api.auth = joe_auth
172
+ expect(:get, "#{github_yaml}/repos/showp/joe007/new_repo")
173
+ repos = described_class.show('arvicco')
174
+ p repos
175
+ p repos.map(&:url)
176
+ repos.should be_an Array
177
+ repos.should_not be_empty
178
+ if repos.last.name == 'new_repo'
179
+ repos.last.delete
180
+ end
181
+ true.should == false
182
+ end
183
+
184
+ # context 'manipulating repos' do
185
+ # before (:each) do
186
+ # @gh = described_class.new('joerepo')
187
+ # @name = "test#{Time.now.to_i}"
188
+ # end
189
+ # after (:each) do
190
+ # @gh.delete_repo @name
191
+ # end
192
+ #
193
+ # it 'creates new repo of a valid github user' do
194
+ # @gh.create_repo @name
195
+ # repos = @gh.repos
196
+ # repos.should_not be_empty
197
+ # repos.last[:name].should == @name
198
+ # end
199
+ #
200
+ # it 'creates SINGLE new repo' do
201
+ # # Problem: sticky cache
202
+ # r = @gh.repos
203
+ # p r
204
+ # n = r.size
205
+ #
206
+ # @gh.create_repo @name
207
+ # sleep 2
208
+ # rr = @gh.repos
209
+ # p rr
210
+ # rr.size.should == n+1
211
+ # end
212
+ #
213
+ # it 'creates and deletes repo of a valid github user' do
214
+ # #creating
215
+ # @gh.create_repo @name
216
+ # repos = @gh.repos
217
+ # repos.should_not be_empty
218
+ # repos.last[:name].should == @name
219
+ #
220
+ # #deleting
221
+ # @gh.delete_repo @name
222
+ # sleep 2
223
+ # repos = @gh.repos
224
+ # repos.last[:name].should_not == @name
225
+ # repos.find {|r|r[:name] == @name}.should == nil
226
+ # #false.should be_true
227
+ # end
228
+ #
229
+ # it 'returns nil if deleting non-existing repo' do
230
+ # result = @gh.delete_repo @name
231
+ # result.should == nil
232
+ # end
233
+ #
234
+ # it 'does not change repos size if deleting non-existing repo' do
235
+ # n = @gh.repos.size
236
+ #
237
+ # @gh.delete_repo @name
238
+ # sleep 1.5
239
+ # @gh.repos.should have(n).repos
240
+ # end
241
+ # end
242
+ #
243
+ end # describe GitHub::Repo
244
+
245
+ end # module GithubTest
246
+
247
+ # EOF
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format nested
@@ -0,0 +1,190 @@
1
+ require 'spec'
2
+ require 'cgi'
3
+ require 'fakeweb'
4
+ require 'fakeweb_matcher'
5
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib git_hub]))
6
+
7
+ # Module that extends RSpec with my own extensions/macros
8
+ module SpecMacros
9
+
10
+ # Wrapper for *it* method that extracts description from example source code, such as:
11
+ # spec{ use{ result = function(arg1 = 4, arg2 = 'string') }}
12
+ def spec &block
13
+ it description_from(*block.source_location), &block
14
+ end
15
+
16
+ # reads description line from source file and drops external brackets (like *spec*{}, *use*{})
17
+ def description_from(file, line)
18
+ File.open(file) do |f|
19
+ f.lines.to_a[line-1].gsub( Regexp.new('(spec.*?{)|(use.*?{)|}'), '' ).lstrip.rstrip
20
+ end
21
+ end
22
+ end
23
+
24
+ Spec::Runner.configure do |config|
25
+ # Add my macros
26
+ config.extend(SpecMacros)
27
+ end
28
+
29
+ module GitHubTest
30
+
31
+ # Test related Constants:
32
+ TEST_PROJECT = 'GitHub'
33
+ TEST_STRING = 'This is test string'
34
+
35
+ # Checks that given block does not raise any errors
36
+ def use
37
+ lambda {yield}.should_not raise_error
38
+ end
39
+
40
+ # Returns empty block (for use in spec descriptions)
41
+ def any_block
42
+ lambda {|*args| args}
43
+ end
44
+
45
+ # Extract response from file
46
+ def response_from_file(path)
47
+ filename = File.join(File.dirname(__FILE__), 'stubs', path + '.res')
48
+ unless File.exists?(filename) && !File.directory?(filename)
49
+ raise "No stub file #{filename}. To obtain it use:\n#{curl_string(path, filename)}"
50
+ end
51
+ filename
52
+ end
53
+
54
+ # Extract response body from file
55
+ def body_from_file(path)
56
+ File.read(response_from_file(path)).gsub(/.*\n\n/m, '')
57
+ end
58
+
59
+ def curl_string(path, filename)
60
+ auth_string = api.authenticated? ? "?login=#{api.auth['login']}&token=#{api.auth['token']}" : ""
61
+ "curl -i #{github_yaml}#{path}#{auth_string} > #{filename}"
62
+ end
63
+
64
+ # Stubs github server, with options:
65
+ # :host:: Host name - default 'github.com'
66
+ # :port:: Port - default 80
67
+ def stub_server(options={})
68
+ server = Net::HTTP.new(options[:host] ||'github.com', options[:port] || 80)
69
+ Net::HTTP.stub!(:new).and_return(server)
70
+ server
71
+ end
72
+
73
+ # Stubs http request, with options:
74
+ # :path:: Request path - default '/api/v2/yaml/repos/create'
75
+ # :get:: Indicates that request is get, otherwise post
76
+ def stub_req(options={})
77
+ path = options[:path] || '/api/v2/yaml/repos/create'
78
+ options[:get] ? Net::HTTP::Get.new(path) : Net::HTTP::Post.new(path)
79
+ end
80
+
81
+ def stub_server_and_req(options = {})
82
+ [stub_server(options), stub_req(options)]
83
+ end
84
+
85
+ # Turns string into appropriate class constant, returns nil if class not found
86
+ def classify name
87
+ klass = name.split("::").inject(Kernel) {|klass, const_name| klass.const_get const_name }
88
+ klass.is_a?(Class) ? klass : nil
89
+ rescue NameError
90
+ nil
91
+ end
92
+
93
+ # Builds fake HTTP response from a given options Hash. Accepts options:
94
+ # :klass:: Response class, default - Net::HTTPOK
95
+ # :http_version:: HTTP version - default 1.1
96
+ # :code:: Response return code - default 200
97
+ # :message:: Response message - default 'OK'
98
+ # :status:: [code, message] pair as one option
99
+ # :body:: Response body - default ''
100
+ # TODO: make it more lifelike using StringIO, instead of just stubbing :body
101
+ def build_response(options={})
102
+ code = options[:status] ? options[:status].first : options[:code] || 200
103
+ message = options[:status] ? options[:status].last : options[:message] || 'OK'
104
+ version = options[:http_version] || 1.1
105
+ resp = (options[:klass] || Net::HTTPOK).new(code, version, message)
106
+ resp.stub!(:body).and_return(options[:body] || '')
107
+ resp
108
+ end
109
+
110
+ # Expects request of certain method(:get, :post, ... :any) to specific uri (given as a String, URI or Regexp),
111
+ # (optionally) matches expected query keys with actuals and handles request and response according to options.
112
+ # In addition to build_response options (:klass, :http_version, :code, :message, :status, :body), it supports:
113
+ # :expected_keys:: Hash of expected query keys(if value is not important, :key => :any)
114
+ # :response:: Use this ready-made response object instead of building response
115
+ # :exception:: Raise this Exception object instead of response
116
+ # If you expect multiple requests to the same uri, options may also be an Array containing a list of the
117
+ # above-described Hashes - requests will be expected in the same order they appear in the Array
118
+ def expects(method, uri, options={})
119
+ @github ||= stub_server
120
+ opts = options.is_a?(Array) ? options.shift : options # may be a single options Hash or Array of Hashes
121
+ @github.should_receive(:request) do |req|
122
+ case method # match expected request method to actual
123
+ when :any
124
+ Net::HTTPRequest
125
+ when Class
126
+ method
127
+ when Symbol, String
128
+ classify('Net::HTTP::' + method.to_s.capitalize)
129
+ end.should === req
130
+ case uri # match expected uri to actual
131
+ when URI::HTTP, URI::HTTPS
132
+ uri.path
133
+ when String
134
+ URI.parse(uri).path
135
+ when Regexp
136
+ uri
137
+ end.should === req.path
138
+ if opts[:expected_keys] # match expected request query keys to actual keys
139
+ actuals = CGI::parse(req.body)
140
+ opts[:expected_keys].each do |key, val|
141
+ actuals.should have_key key.to_s
142
+ actual = actuals[key.to_s]
143
+ actual = actual.first if actual.size == 1 # if only one array element, extract it
144
+ case val # match expected key value to actual
145
+ when :any
146
+ when Class, Regexp, String
147
+ val.should === actual
148
+ else
149
+ val.to_s.should === actual
150
+ end
151
+ end
152
+ end
153
+ expects(method, uri, options) if options.is_a?(Array) && !options.empty? # expect next request in Array
154
+ raise opts[:exception] if opts[:exception] && opts[:exception].kind_of?(Exception)
155
+ opts[:response] || build_response(opts)
156
+ end
157
+ end
158
+
159
+ # Extends path to uri, registers it with FakeWeb with stub file at stubs/path as a response
160
+ # If block is given, yields to block and checks that registered uri was hit during block execution
161
+ def expect(method, path)
162
+ case path
163
+ when Regexp.new(github_yaml)
164
+ uri = path
165
+ file = path.sub(github_yaml, '')
166
+ else
167
+ uri = github_yaml + path
168
+ file = path
169
+ end
170
+ FakeWeb.register_uri(method, uri, :response=>response_from_file(file))
171
+ if block_given?
172
+ yield
173
+ FakeWeb.should have_requested(method, uri)
174
+ end
175
+ end
176
+
177
+ # Auth for joe
178
+ def joe_auth
179
+ {'login' => 'joe007', 'token' => 'b937c8e7ea5a5b47f94eafa39b1e0462'}
180
+ end
181
+
182
+ def github_yaml
183
+ 'http://github.com/api/v2/yaml'
184
+ end
185
+
186
+ def api
187
+ GitHub::Api.instance
188
+ end
189
+
190
+ end # module GithubTest
@@ -0,0 +1,24 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.61
3
+ Date: Wed, 30 Dec 2009 14:17:37 GMT
4
+ Content-Type: application/x-yaml; charset=utf-8
5
+ Connection: keep-alive
6
+ Status: 200 OK
7
+ ETag: "3448dffce35f5b38d4e477cd57aa7249"
8
+ X-Runtime: 76ms
9
+ Content-Length: 235
10
+ Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
11
+ Cache-Control: private, max-age=0, must-revalidate
12
+
13
+ ---
14
+ repository:
15
+ :url: http://github.com/joe007/new_repo
16
+ :description: New repo
17
+ :forks: 0
18
+ :open_issues: 0
19
+ :homepage: http://joe.org/new_repo
20
+ :fork: false
21
+ :private: false
22
+ :name: new_repo
23
+ :owner: joe007
24
+ :watchers: 1
@@ -0,0 +1,14 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.61
3
+ Date: Wed, 30 Dec 2009 15:04:15 GMT
4
+ Content-Type: application/x-yaml; charset=utf-8
5
+ Connection: keep-alive
6
+ Status: 200 OK
7
+ ETag: "71c252d33cdcaab261e3adea39b35dcc"
8
+ X-Runtime: 7ms
9
+ Content-Length: 30
10
+ Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
11
+ Cache-Control: private, max-age=0, must-revalidate
12
+
13
+ ---
14
+ delete_token: jtytnzdcdk
@@ -0,0 +1,14 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.61
3
+ Date: Wed, 30 Dec 2009 15:05:59 GMT
4
+ Content-Type: application/x-yaml; charset=utf-8
5
+ Connection: keep-alive
6
+ Status: 200 OK
7
+ ETag: "2805d28a06ffb58479b7a08117a67714"
8
+ X-Runtime: 23ms
9
+ Content-Length: 21
10
+ Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
11
+ Cache-Control: private, max-age=0, must-revalidate
12
+
13
+ ---
14
+ status: deleted
@@ -0,0 +1,54 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.61
3
+ Date: Wed, 30 Dec 2009 10:59:42 GMT
4
+ Content-Type: application/x-yaml; charset=utf-8
5
+ Connection: keep-alive
6
+ Status: 200 OK
7
+ ETag: "173a8304817dc5a17d79f49e4b7af5b4"
8
+ X-Runtime: 48ms
9
+ Content-Length: 8727
10
+ Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
11
+ Cache-Control: private, max-age=0, must-revalidate
12
+
13
+ ---
14
+ repositories:
15
+ - name: fine_repo
16
+ size: 1228
17
+ followers: 3
18
+ username: joe007
19
+ language: ""
20
+ fork: false
21
+ id: repo-270000
22
+ type: repo
23
+ pushed: "2009-11-11T22:58:52Z"
24
+ forks: 0
25
+ description: Fine repo by joe
26
+ score: 4.918499
27
+ created: "2009-08-06T00:20:39Z"
28
+ - name: another_repo
29
+ size: 224
30
+ followers: 1
31
+ username: joe007
32
+ language: ""
33
+ fork: false
34
+ id: repo-270001
35
+ type: repo
36
+ pushed: "2009-09-15T22:27:51Z"
37
+ forks: 1
38
+ description: Another fine repo by joe
39
+ score: 0.66973364
40
+ created: "2009-05-27T03:18:32Z"
41
+ - name: private_repo
42
+ size: 656
43
+ followers: 1
44
+ username: joe007
45
+ language: ""
46
+ fork: false
47
+ id: repo-26145
48
+ type: repo
49
+ pushed: "2009-11-22T18:09:13Z"
50
+ forks: 0
51
+ description: Private repo by joe
52
+ score: 1.9410602
53
+ created: "2008-06-17T19:51:25Z"
54
+
@@ -0,0 +1,14 @@
1
+ HTTP/1.1 403 Forbidden
2
+ Server: nginx/0.7.61
3
+ Date: Wed, 30 Dec 2009 13:12:41 GMT
4
+ Content-Type: application/x-yaml; charset=utf-8
5
+ Connection: keep-alive
6
+ Status: 403 Forbidden
7
+ X-Runtime: 8ms
8
+ Content-Length: 43
9
+ Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
10
+ Cache-Control: no-cache
11
+
12
+ ---
13
+ error:
14
+ - error: repository not found
@@ -0,0 +1,24 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.61
3
+ Date: Wed, 30 Dec 2009 13:21:54 GMT
4
+ Content-Type: application/x-yaml; charset=utf-8
5
+ Connection: keep-alive
6
+ Status: 200 OK
7
+ ETag: "7d6e90fc96569a71927a11994c8125ad"
8
+ X-Runtime: 14ms
9
+ Content-Length: 224
10
+ Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
11
+ Cache-Control: private, max-age=0, must-revalidate
12
+
13
+ ---
14
+ repository:
15
+ :url: http://github.com/joe007/fine_repo
16
+ :description: Fine repo by joe
17
+ :open_issues: 0
18
+ :homepage: ""
19
+ :forks: 0
20
+ :fork: false
21
+ :private: false
22
+ :name: fine_repo
23
+ :owner: joe007
24
+ :watchers: 1
@@ -0,0 +1,24 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.61
3
+ Date: Wed, 30 Dec 2009 14:34:15 GMT
4
+ Content-Type: application/x-yaml; charset=utf-8
5
+ Connection: keep-alive
6
+ Status: 200 OK
7
+ ETag: "62c142268ede730d1035636172c65318"
8
+ X-Runtime: 8ms
9
+ Content-Length: 235
10
+ Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
11
+ Cache-Control: private, max-age=0, must-revalidate
12
+
13
+ ---
14
+ repository:
15
+ :url: http://github.com/joe007/new_repo
16
+ :description: New repo
17
+ :open_issues: 0
18
+ :homepage: http://joe.org/new_repo
19
+ :fork: false
20
+ :private: false
21
+ :name: new_repo
22
+ :owner: joe007
23
+ :watchers: 1
24
+ :forks: 0
@@ -0,0 +1,44 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.61
3
+ Date: Tue, 29 Dec 2009 15:54:21 GMT
4
+ Content-Type: application/x-yaml; charset=utf-8
5
+ Connection: keep-alive
6
+ Status: 200 OK
7
+ ETag: "67456d99562ca82c4e70efcc72b9f5ef"
8
+ X-Runtime: 13ms
9
+ Content-Length: 661
10
+ Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
11
+ Cache-Control: private, max-age=0, must-revalidate
12
+
13
+ ---
14
+ repositories:
15
+ - :url: http://github.com/joe007/fine_repo
16
+ :description: Fine repo by joe
17
+ :forks: 0
18
+ :open_issues: 0
19
+ :homepage: ""
20
+ :fork: false
21
+ :private: false
22
+ :name: fine_repo
23
+ :owner: joe007
24
+ :watchers: 3
25
+ - :url: http://github.com/joe007/another_repo
26
+ :description: Another fine repo by joe
27
+ :forks: 0
28
+ :open_issues: 0
29
+ :homepage: ""
30
+ :fork: false
31
+ :private: false
32
+ :name: another_repo
33
+ :owner: joe007
34
+ :watchers: 1
35
+ - :url: http://github.com/joe007/private_repo
36
+ :description: Private repo by joe
37
+ :forks: 0
38
+ :open_issues: 0
39
+ :homepage: ""
40
+ :fork: false
41
+ :private: false
42
+ :name: private_repo
43
+ :owner: joe007
44
+ :watchers: 1
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git_hub
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Arvicco
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-05 00:00:00 +03:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bones
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 3.2.0
24
+ version:
25
+ description: |-
26
+ git_hub is a library that wraps github API and exposes simple interface for
27
+ finding, creating and managing github repositories and other resources.
28
+ email: arvitallian@gmail.com
29
+ executables:
30
+ - git_hub
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - History.txt
35
+ - README.txt
36
+ - bin/git_hub
37
+ files:
38
+ - History.txt
39
+ - README.txt
40
+ - Rakefile
41
+ - bin/git_hub
42
+ - lib/git_hub.rb
43
+ - lib/git_hub/api.rb
44
+ - lib/git_hub/base.rb
45
+ - lib/git_hub/repo.rb
46
+ - spec/git_hub/api_spec.rb
47
+ - spec/git_hub/base_spec.rb
48
+ - spec/git_hub/repo_spec.rb
49
+ - spec/spec.opts
50
+ - spec/spec_helper.rb
51
+ - spec/stubs/repos/create.res
52
+ - spec/stubs/repos/delete/new_repo.1.res
53
+ - spec/stubs/repos/delete/new_repo.2.res
54
+ - spec/stubs/repos/search/joe+repo.res
55
+ - spec/stubs/repos/show/joe007.res
56
+ - spec/stubs/repos/show/joe007/err_repo.res
57
+ - spec/stubs/repos/show/joe007/fine_repo.res
58
+ - spec/stubs/repos/show/joe007/new_repo.res
59
+ has_rdoc: true
60
+ homepage: http://github.com/arvicco/git_hub
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --main
66
+ - README.txt
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ requirements: []
82
+
83
+ rubyforge_project: git_hub
84
+ rubygems_version: 1.3.5
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: git_hub is a library that wraps github API and exposes simple interface for finding, creating and managing github repositories and other resources
88
+ test_files: []
89
+