git_hub 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+